﻿using _80X_CG_Frame.Objects;
using _80X_CG_Frame.Protocols;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System.Threading;
using System.Threading.Tasks;

namespace _80X_CG_Frame.Workers
{
    /// <summary>
    /// 测试模板类
    /// </summary>
    public class RunWorker_802 : WorkerBase
    {
        #region 线程全局变量
        public int interval = 50;
        private int debug_delay = 300;

        private StreamWriter camera_log_file;
        private StreamWriter warning_file;

        bool has_wrong = false;
        private int max_check_count = 20;
        private int check_count = 0;
        private int max_sfc_count = 6000;//sfc预热刷新时间,1次约等于100ms
        private int sfc_count = 0;//sfc预热计数
        private int cg_NG = 0;
        //private JArray jArray_laser_param = new JArray();
        private int 屏蔽片_NG = 0;
        private int 螺母_NG = 0;
        private int 螺母连续_NG = 0;
        private int max_wait_time = 1000;//最大等待时间ms
        private int max_wait;//最大等待次数
        Dictionary<string, bool> connect_flags;//连接中的标志,避免重连刷屏
        private static int max_fail = 5;//扫码失败最大重试次数
        //出错统计
        private Dictionary<string, int> error_flags = new Dictionary<string, int>();
        private static int max_error = 5;

        static double 角度转换上螺母脉冲系数 = 138.8888;
        static double 角度转换上屏蔽片脉冲系数 = 55.5555;
        static double OffsetToPulse系数 = 10000;
        // private static int cg条码ok统计 = 0;
        // private static int cg条码ng统计 = 0;
        #endregion
        public RunWorker_802()
        {
            connect_flags = new Dictionary<string, bool>();
            max_wait = max_wait_time / interval;
        }
        protected override void Run()
        {
            Init();
            while (loop)
            {
                Work();
                CheckStatus();
                System.Threading.Thread.Sleep(100);
            }
            Exit();
        }

        private void Init()
        {
            GLOBAL.统计数据.启动时间 = DateTime.Now;
            //如果视觉未启动则启动视觉
            if (Process.GetProcessesByName("SmartCAM").Count() == 0)
                Process.Start(GLOBAL.config.Get("camera_process_path"));

                //日志文件
            string log_folder_path = GLOBAL.config.Get("log_folder_path");
            string data_file_path = log_folder_path + @"\" + DateTime.Now.ToString("yyyyMMdd HH-mm-ss") + @".csv";
            camera_log_file = new StreamWriter(data_file_path, true)
            {
                AutoFlush = true
            };
            //告警信息文件
            string warning_folder_path = GLOBAL.config.Get("warning_folder_path");
            string warning_file_path = warning_folder_path + @"\" + GLOBAL.GetMondayDate(DateTime.Now).ToString("yyyyMMdd") + "-" 
                + GLOBAL.GetSundayDate(DateTime.Now).ToString("yyyyMMdd") + @".csv";
            //string warning_file_path = warning_folder_path + @"\" + DateTime.Now.ToString("yyyyMMdd HH-mm-ss") + @".csv";
            warning_file = new StreamWriter(warning_file_path, true)
            {
                AutoFlush = true
            };

            #region 开始连接
            Log.Write("工作线程启动");
            //SFC连接预热
            var t = new JObject();
            t["host_ip"] = "127.0.0.1";
            
            Task.Run(() =>
            {
                GLOBAL.sfc.上料确认(t).ContinueWith(f =>
                {
                    if (f.Result)
                        Log.Write("SFC上料确认预热完成");
                    else
                        Log.Write("SFC上料确认预热失败");
                });
            });
            Task.Run(() =>
            {
                GLOBAL.sfc.参数上传(t).ContinueWith(f =>
                {
                    if (f.Result)
                        Log.Write("SFC参数上传预热完成");
                    else
                        Log.Write("SFC参数上传预热失败");
                });
            });
            //初始化任务队列
            var tasks = new List<Task>();

            
            //连接相机
            tasks.Add(GLOBAL.cameras.CamConnectAsync(
                GLOBAL.config.Get("相机视觉_address"),
                1));

            //连接PLC
            /*
            tasks.Add(GLOBAL.plc.ConnectAsync(
                GLOBAL.config.Get("PLC_address"),
                1));
                */
            for(int i = 0;i < 5;i++)
            {
                try
                {
                    if(!GLOBAL.plc.IsConnect)
                        GLOBAL.plc.Connect(GLOBAL.config.Get("PLC_address"), 1);
                }
                catch(Exception e)
                {
                    Log.Write(e.ToString());
                }
            }
            //连接SFC服务器
            /*
            tasks.Add(GLOBAL.sfc.ConnectAsync(
                GLOBAL.config.Get("SFC服务器_address"),
                1));
                */

            //连接激光机台
            foreach (string laser_name in GLOBAL.laser.Keys)
            {
                tasks.Add(GLOBAL.laser[laser_name].ConnectAsync(
                    GLOBAL.config.Get(laser_name + "_address"),
                    1));
            }

            //连接扫码枪
            foreach (string 扫码枪_name in GLOBAL.扫码枪.Keys)
            {
                tasks.Add(GLOBAL.扫码枪[扫码枪_name].ConnectAsync(
                    GLOBAL.config.Get(扫码枪_name+"_address"),
                    1));
            }
            //连接扫码枪
            //tasks.Add(GLOBAL.扫码枪.ConnectAsync(
            //    GLOBAL.config.Get("扫码枪_address"),
            //    1));
            //连接机器手
            foreach (string robot_name in GLOBAL.robot.Keys)
            {
                tasks.Add(GLOBAL.robot[robot_name].ConnectAsync(
                    GLOBAL.config.Get(robot_name + "_address"),
                    1));
            }

            //等待所有初始化任务完成
            Task finish_task = Task.WhenAll(tasks);
            try
            {
                finish_task.Wait();
            }
            catch { }
            

            //统计初始化状态
            if (!GLOBAL.cameras.IsConnect)
            {
                has_wrong = true;
                Log.Write("相机视觉连接失败");
            }

            if (!GLOBAL.plc.IsConnect)
            {
                has_wrong = true;
                Log.Write("PLC连接失败");
            }
            foreach (string laser_name in GLOBAL.laser.Keys)
            {
                if (!GLOBAL.laser[laser_name].IsConnect)
                {
                    has_wrong = true;
                    Log.Write(laser_name + "连接失败");
                }
            }
            //SFC日志连接失败时仍然可以运行
            /*
            if (!GLOBAL.logUpload.IsConnect)
            {
                Log.Write("SFC服务器连接失败");
            }
            */

            foreach (string 扫码枪_name in GLOBAL.扫码枪.Keys)
            {
                if (!GLOBAL.扫码枪[扫码枪_name].IsConnect)
                {
                    has_wrong = true;
                    Log.Write("扫码枪连接失败");
                }
            }

            foreach (string robot_name in GLOBAL.robot.Keys)
            {
                if (!GLOBAL.robot[robot_name].IsConnect)
                {
                    has_wrong = true;
                    Log.Write(robot_name + "连接失败");
                }
            }

            if (finish_task.Status != TaskStatus.RanToCompletion
                && !has_wrong)
                Log.Write("工作线程初始化完成");
            else
                Log.Write("工作线程初始化失败");

            #endregion
            try
            {
                if (GLOBAL.cameras.IsConnect)
                {
                    //临时延时,防止视觉未启动完成时发送指令
                    Thread.Sleep(5000);
                    //初始化相机模板
                    var 默认模板 = GLOBAL.config.configs["相机参数"]["默认模板"];
                    var 空模板 = GLOBAL.config.configs["相机参数"]["空模板"];

                    //切换到空任务
                    GLOBAL.cameras.SelectTask(0, (int)空模板["相机0"]);
                    GLOBAL.cameras.SelectTask(1, (int)空模板["相机1"]);
                    GLOBAL.cameras.SelectTask(2, (int)空模板["相机2"]);
                    GLOBAL.cameras.SelectTask(3, (int)空模板["相机3"]);
                    GLOBAL.cameras.SelectTask(4, (int)空模板["相机4"]);
                    GLOBAL.cameras.SelectTask(5, (int)空模板["相机5"]);
                    GLOBAL.cameras.SelectTask(6, (int)空模板["相机6"]);
                    //切换到默认模板
                    GLOBAL.cameras.SelectTask(0, (int)默认模板["相机0"]);
                    GLOBAL.cameras.SelectTask(1, (int)默认模板["相机1"]);
                    GLOBAL.cameras.SelectTask(2, (int)默认模板["相机2"]);
                    GLOBAL.cameras.SelectTask(3, (int)默认模板["相机3"]);
                    GLOBAL.cameras.SelectTask(4, (int)默认模板["相机4"]);
                    GLOBAL.cameras.SelectTask(5, (int)默认模板["相机5"]);
                    GLOBAL.cameras.SelectTask(6, (int)默认模板["相机6"]);
                }
            }
            catch (Exception e)
            {
                Log.Write(e.Message);
            }


            //Task.Run(new Action(上螺母料盘检测方法));
            Task.Run(new Action(上螺母触发方法));
            Task.Run(new Action(螺母检测触发方法));
            Task.Run(new Action(上cg扫码触发方法));
            Task.Run(new Action(上屏蔽片触发方法));
            Task.Run(new Action(下cg扫码枪触发方法));
            Task.Run(new Action(刷新PLC方法));
            Task.Run(new Action(模拟回环线方法));
            Task.Run(new Action(保存打印警告信息));

        }

        private void Work()
        {
            if (GLOBAL.laser["激光机台2"].IsConnect)
            {
                string result = "";
                //GLOBAL.laser["激光机台2"].GetNutParamJson(ref result);
               // JObject jobject = LaserEngine.GetLaserConfigs(result);
            }

            /*
            for (int i = 0; i < 100; i++)
                Log.Write("工作中");
                */
            //回环线

        }
        /// <summary>
        /// 检测连接(带重连)
        /// </summary>
        private void CheckStatus()
        {
            try
            {
                check_count++;
                if (check_count >= max_check_count)
                {
                    check_count = 0;

                    if (Process.GetProcessesByName("SmartCAM").Count() == 0)
                    {
                        //相机视觉进程重连
                        Process.Start(GLOBAL.config.Get("camera_process_path"));
                        Thread.Sleep(5000);
                        //初始化相机模板
                        var 默认模板 = GLOBAL.config.configs["相机参数"]["默认模板"];
                        var 空模板 = GLOBAL.config.configs["相机参数"]["空模板"];

                        //切换到空任务
                        GLOBAL.cameras.SelectTask(0, (int)空模板["相机0"]);
                        GLOBAL.cameras.SelectTask(1, (int)空模板["相机1"]);
                        GLOBAL.cameras.SelectTask(2, (int)空模板["相机2"]);
                        GLOBAL.cameras.SelectTask(3, (int)空模板["相机3"]);
                        GLOBAL.cameras.SelectTask(4, (int)空模板["相机4"]);
                        GLOBAL.cameras.SelectTask(5, (int)空模板["相机5"]);
                        GLOBAL.cameras.SelectTask(6, (int)空模板["相机6"]);
                        //切换到默认模板
                        GLOBAL.cameras.SelectTask(0, (int)默认模板["相机0"]);
                        GLOBAL.cameras.SelectTask(1, (int)默认模板["相机1"]);
                        GLOBAL.cameras.SelectTask(2, (int)默认模板["相机2"]);
                        GLOBAL.cameras.SelectTask(3, (int)默认模板["相机3"]);
                        GLOBAL.cameras.SelectTask(4, (int)默认模板["相机4"]);
                        GLOBAL.cameras.SelectTask(5, (int)默认模板["相机5"]);
                        GLOBAL.cameras.SelectTask(6, (int)默认模板["相机6"]);
                    }
                    //相机重连
                    if (!GLOBAL.cameras.IsConnect)
                    {
                        if (!connect_flags.ContainsKey("camera"))
                        {
                            Log.Write("相机视觉已断开连接");
                            Log.Write("相机视觉重新连接中");
                            connect_flags["camera"] = true;
                        }
                        GLOBAL.cameras.CamConnectAsync(GLOBAL.config.Get("相机视觉_address"), 1).Wait();
                        //重连后设置模板动作(改为切换模板后会删除)
                        if (GLOBAL.cameras.IsConnect)
                        {
                            //临时延时,防止视觉未启动完成时发送指令
                            Thread.Sleep(5000);
                            //初始化相机模板
                            var 相机模板 = GLOBAL.config.configs["相机参数"]["默认模板"];
                            GLOBAL.cameras.SelectTask(0, (int)相机模板["相机0"]);
                            GLOBAL.cameras.SelectTask(1, (int)相机模板["相机1"]);
                            GLOBAL.cameras.SelectTask(2, (int)相机模板["相机2"]);
                            GLOBAL.cameras.SelectTask(3, (int)相机模板["相机3"]);
                            GLOBAL.cameras.SelectTask(4, (int)相机模板["相机4"]);
                            GLOBAL.cameras.SelectTask(5, (int)相机模板["相机5"]);
                            GLOBAL.cameras.SelectTask(6, (int)相机模板["相机6"]);
                        }
                    }
                    else if (connect_flags.ContainsKey("camera"))
                    {
                        Log.Write("相机视觉重新连接成功");
                        connect_flags.Remove("camera");
                    }
                    
                    foreach (string laser_name in GLOBAL.laser.Keys)
                    {
                        if (!GLOBAL.laser[laser_name].IsConnect)
                        {
                            if (!connect_flags.ContainsKey(laser_name))
                            {
                                Log.Write(laser_name + "已断开连接");
                                Log.Write(laser_name + "重新连接中");
                                connect_flags[laser_name] = true;
                            }
                            GLOBAL.laser[laser_name].ConnectAsync(GLOBAL.config.Get(laser_name + "_address"), 1).Wait();
                        }
                        else if (connect_flags.ContainsKey(laser_name))
                        {
                            connect_flags.Remove(laser_name);
                            Log.Write(laser_name + "重新连接成功");
                        }
                    }
                    //if (!GLOBAL.logUpload.IsConnect)
                    //{
                    //    Log.Write("SFC服务器已断开连接");
                    //}
                    //plc重连
                    if (!GLOBAL.plc.IsConnect)
                    {
                        if (!connect_flags.ContainsKey("plc"))
                        {
                            Log.Write("PLC已断开连接");
                            Log.Write("PLC重新连接");
                            connect_flags["plc"] = true;
                        }
                        GLOBAL.plc.Connect(GLOBAL.config.Get("PLC_address"), 1);
                    }
                    else if (connect_flags.ContainsKey("plc"))
                    {
                        connect_flags.Remove("plc");
                        Log.Write("PLC重新连接成功");
                    }
                    foreach (string 扫码枪_name in GLOBAL.扫码枪.Keys)
                    {
                        //扫码枪重连
                        if (!GLOBAL.扫码枪[扫码枪_name].IsConnect)
                        {
                            if (!connect_flags.ContainsKey(扫码枪_name))
                            {
                                Log.Write(扫码枪_name + "已断开连接");
                                Log.Write(扫码枪_name + "重新连接中");
                                connect_flags[扫码枪_name] = true;
                            }
                            GLOBAL.扫码枪[扫码枪_name].ConnectAsync(GLOBAL.config.Get(扫码枪_name + "_address"), 1).Wait();
                        }
                        else if (connect_flags.ContainsKey(扫码枪_name))
                        {
                            connect_flags.Remove(扫码枪_name);
                            Log.Write(扫码枪_name + "重新连接成功");
                        }
                    }

                    //机器手重连
                    foreach (string robot_name in GLOBAL.robot.Keys)
                    {
                        if (!GLOBAL.robot[robot_name].IsConnect)
                        {
                            if (!connect_flags.ContainsKey(robot_name))
                            {
                                Log.Write(robot_name + "已断开连接");
                                Log.Write(robot_name + "重新连接中");
                                connect_flags[robot_name] = true;
                            }
                            GLOBAL.robot[robot_name].ConnectAsync(GLOBAL.config.Get(robot_name + "_address"), 1).Wait();
                        }
                        else if (connect_flags.ContainsKey(robot_name))
                        {
                            connect_flags.Remove(robot_name);
                            Log.Write(robot_name + "重新连接成功");
                        }
                    }

                }
                sfc_count++;
                if(sfc_count >= max_sfc_count)
                {
                    sfc_count = 0;
                    //SFC连接预热
                    var t = new JObject();
                    t["host_ip"] = "127.0.0.1";

                    Task.Run(() =>
                    {
                        GLOBAL.sfc.上料确认(t).ContinueWith(f =>
                        {
                            if (f.Result)
                                Log.Write("SFC上料确认预热完成");
                            else
                                Log.Write("SFC上料确认预热失败");
                        });
                    });
                    Task.Run(() =>
                    {
                        GLOBAL.sfc.参数上传(t).ContinueWith(f =>
                        {
                            if (f.Result)
                                Log.Write("SFC参数上传预热完成");
                            else
                                Log.Write("SFC参数上传预热失败");
                        });
                    });
                }
            }
            catch (Exception e)
            {
                Log.Write("检查状态异常"+e.Message);
            }
          

          
        }

        private void Exit()
        {
            Log.Write("下cg条码ok次数:" + GLOBAL.统计数据.下CG_Count_OK);
            Log.Write("下cg条码ng次数:" + GLOBAL.统计数据.下CG_Count_NG);
            Log.Write("上cg条码ok次数:" + GLOBAL.统计数据.上CG_Count_OK);
            Log.Write("上cg条码ng次数:" + GLOBAL.统计数据.上CG_Count_NG);
            Log.Write("回环线动作数:" + GLOBAL.统计数据.回环线动作数);
            Log.Write("回环线动作平均时间:" + GLOBAL.统计数据.回环线动作平均时间);
            if (GLOBAL.cameras.IsConnect)
            {
                Log.Write("相机算法已断开连接");
                GLOBAL.cameras.DisConnect();
            }

            if (GLOBAL.plc.IsConnect)
            {
                Log.Write("PLC已断开连接");
                GLOBAL.plc.Disconnect();
            }
            foreach (string laser_name in GLOBAL.laser.Keys)
            {
                if (GLOBAL.laser[laser_name].IsConnect)
                {
                    Log.Write(laser_name + "已断开连接");
                    GLOBAL.laser[laser_name].DisConnect();
                }
            }
            if (GLOBAL.logUpload.IsConnect)
            {
                Log.Write("SFC服务器已断开连接");
                GLOBAL.logUpload.DisConnect();

            }
            foreach (string 扫码枪_name in GLOBAL.扫码枪.Keys)
            {
                if (GLOBAL.扫码枪[扫码枪_name].IsConnect)
                {
                    Log.Write(扫码枪_name+"已断开连接");
                    GLOBAL.扫码枪[扫码枪_name].DisConnect();
                }
            }

            foreach (string robot_name in GLOBAL.robot.Keys)
            {
                if (GLOBAL.robot[robot_name].IsConnect)
                {
                    Log.Write(robot_name + "已断开连接");
                    GLOBAL.robot[robot_name].DisConnect();

                }
            }
            camera_log_file.Close();
            warning_file.Close();
            Log.Write("工作线程退出");
        }

        private void 上螺母料盘检测方法()
        {
            while (loop)
            {
                try
                {
                    if (GLOBAL.plc.IsConnect && GLOBAL.cameras.IsConnect && GLOBAL.运行标志 == "1")
                    {
                        /*
                        for (int i=0;i<8;i++)
                        {
                            //判断相机第几次拍照
                            while (!GLOBAL.plc.)
                            {
                                Thread.Sleep(50);
                            }
                            Thread.Sleep(debug_delay);
                            Result r = GLOBAL.cameras.GetTaskStatus(0);
                            Log.Write("第" + i + "次拍料盘状态" + r);
                            if (r == Result.Passed)
                            {
                                int count = GLOBAL.cameras.GetBlobCountResult(Camera.Address[1], 64);
                                int temp = 15 - count;
                                if (temp == 0)
                                {
                                    //让PLC执行下一次拍照
                                    continue;
                                }
                                else
                                {
                                    //让PLC执行吸料
                                    int test_count = i*15 + temp;
                                    break;
                                }
                            }
                            else
                            {

                            }
                        }
                        */
                    }
                } catch (Exception e)
                {
                    Log.Write(e.Message);
                }
                Thread.Sleep(interval);
            }
        }
        /// <summary>
        /// 实际使用相机0,1
        /// </summary>
        private void 上螺母触发方法()
        {
            while (loop)
            {
                try
                {
                    if (GLOBAL.plc.IsConnect && GLOBAL.cameras.IsConnect && GLOBAL.运行标志 == "1" && GLOBAL.总警告 == "0")
                    {
                        string 相机1触发 = "0";//吸螺母上相机
                        string 吸螺母到达二次拍照位置 = "0";//吸螺母上相机
                        string 相机2触发 = "0";//吸螺母下相机

                        GLOBAL.plc.ReadMBit(GLOBAL.config.Get("相机1触发_register"), ref 相机1触发);
                        GLOBAL.plc.ReadMBit(GLOBAL.config.Get("吸螺母到达二次拍照位置_register"), ref 吸螺母到达二次拍照位置);
                        GLOBAL.plc.ReadMBit(GLOBAL.config.Get("相机2触发_register"), ref 相机2触发);

                        if (相机2触发 == "1")
                        {
                            bool has_wrong = false;
                            var 相机0模板0参数 = GLOBAL.config.configs["相机参数"]["相机0"]["模板0"];
                            var blob = 相机0模板0参数["blob"];
                            var 相机1模板2参数 = GLOBAL.config.configs["相机参数"]["相机1"]["模板2"];
                            var 圆1 = 相机1模板2参数["圆1"];
                            var 圆2 = 相机1模板2参数["圆2"];
                            var 轮廓 = 相机1模板2参数["轮廓"];
                            var 边缘 = 相机1模板2参数["边缘"];
                            var 圆1基准点 = 圆1["基准点"].ToArray().Select(x => (double)x).ToArray();
                            var 圆2基准点 = 圆2["基准点"].ToArray().Select(x => (double)x).ToArray();
                            //var 轮廓匹配1基准点 = 相机1模板2参数["轮廓匹配1基准点"].ToArray().Select(x => (double)x).ToArray();
                            var 轮廓匹配2基准点 = 轮廓["基准点"].ToArray().Select(x => (double)x).ToArray();
                            double 相机1边缘基准角度 = (double)边缘["基准角度"];
                            int[] 吸螺母放料位置1 = GLOBAL.config.configs["相机参数"]["吸螺母放料位置1"].ToArray().Select(x => (int)(double)x).ToArray();
                            int[] 吸螺母放料位置2 = GLOBAL.config.configs["相机参数"]["吸螺母放料位置2"].ToArray().Select(x => (int)(double)x).ToArray();
                            int[] 吸螺母抛料位置 = GLOBAL.config.configs["相机参数"]["吸螺母抛料位置"].ToArray().Select(x => (int)(double)x).ToArray();
                            double[] 相机1左偏移测试 = { 0, 0, 0 };
                            //Thread.Sleep(interval);
                            //临时延时
                            //Thread.Sleep(500);
                            Result r1 = Result.None;
                            for (int i = 0; i < max_wait; i++)
                            {
                                r1 = GLOBAL.cameras.GetTaskStatus(1);
                                if (r1 != Result.None)
                                    break;
                                Thread.Sleep(interval);

                            }
                            // Result r1 = GLOBAL.cameras.GetTaskStatus(1);
                            Log.Write("相机1第一次:" + r1.ToString());
                            if (r1 == Result.Passed)
                            {
                                //第一次拍照
                                //string[] 相机1左轮廓 = GLOBAL.cameras.GetContourResult(Camera.Address[1], 111);
                                string[] 相机1左圆 = GLOBAL.cameras.GetCircleResult(
                                       Camera.AddressOffset(
                                        Camera.Address[1],
                                        (int)圆1["起始地址"]),
                                       (int)圆1["长度"]);
                                string[] 相机1右圆 = GLOBAL.cameras.GetCircleResult(
                                        Camera.AddressOffset(
                                        Camera.Address[1],
                                        (int)圆2["起始地址"]),
                                        (int)圆2["长度"]);
                                string[] 相机1右轮廓 = GLOBAL.cameras.GetContourResult(
                                        Camera.AddressOffset(
                                        Camera.Address[1],
                                        (int)轮廓["起始地址"]),
                                        (int)轮廓["长度"]);
                                string[] 相机1边缘 = GLOBAL.cameras.GetEdgeResult(
                                        Camera.AddressOffset(
                                        Camera.Address[1],
                                        (int)边缘["起始地址"]),
                                        (int)边缘["长度"]);
                                //  string[] 相机1右轮廓 = GLOBAL.cameras.GetContourResult(Camera.AddressOffset(Camera.Address[1], 112), 111);
                                // string[] 相机1右圆 = GLOBAL.cameras.GetCircleResult(Camera.AddressOffset(Camera.Address[1], 239), 15);
                               //  string[] 相机1边缘 = GLOBAL.cameras.GetEdgeResult(Camera.AddressOffset(Camera.Address[1], 254), 16);
                                double[] 相机1左偏移 = { 0, 0, 0 };
                                double[] 相机1右偏移 = { 0, 0, 0 };
                                //double[] 相机1右偏移 = { 相机1右圆[0], 相机1右圆[1], 相机1右轮廓[3] };

                                //偏移量计算
                                double offset_x1 = 圆1基准点[0] - Convert.ToDouble(相机1左圆[0]);
                                double offset_y1 = 圆1基准点[1] - Convert.ToDouble(相机1左圆[1]);
                                //double radius1 = 轮廓匹配1基准点[2] - Convert.ToDouble(相机1左轮廓[3]);
                                double offset_x2 = 圆2基准点[0] - Convert.ToDouble(相机1右圆[0]);
                                double offset_y2 = 圆2基准点[1] - Convert.ToDouble(相机1右圆[1]);
                                double radius2 = 轮廓匹配2基准点[2] - Convert.ToDouble(相机1右轮廓[3]);
                                double radius_edge= 相机1边缘基准角度- Convert.ToDouble(相机1边缘[0]);

                                //测试单拍数据
                                double[] 测试左偏移 = new double[] { offset_x1,offset_y1, radius_edge };
                                double[] 测试右偏移 = new double[] { offset_x2, offset_y2, radius2 };
                                string offset_true =
                                    DateTime.Now + "," + "上螺母相机1第一次左螺母偏移" + "," + string.Join(",", 测试左偏移) + "\n" +
                                    DateTime.Now + "," + "上螺母相机1第一次右螺母偏移" + "," + string.Join(",", 测试右偏移);
                                camera_log_file.WriteLine(offset_true);

                                if (radius2 < -2)
                                {
                                    offset_y2 -= 0.01;
                                }
                                if (-5 < radius_edge && radius_edge <= -2)
                                {
                                    offset_x1 += 0.01;
                                }
                                else if (radius_edge <= -5)
                                {
                                    offset_x1 += 0.02;
                                }

                                if (-2 < radius_edge && radius_edge <= -1)
                                {
                                    offset_y1 -= 0.01;
                                }
                                else if (-4 < radius_edge && radius_edge <= -2)
                                {
                                    offset_y1 -= 0.03;
                                }
                                else if (-5< radius_edge && radius_edge <= -4)
                                {
                                    offset_y1 -= 0.04;
                                }
                                else if (-7 < radius_edge && radius_edge <= -5)
                                {
                                    offset_y1 -= 0.06;
                                }
                                else if (-8 < radius_edge && radius_edge <= -7)
                                {
                                    offset_y1 -= 0.07;
                                }
                                else if (1.5 < radius_edge && radius_edge <= 3)
                                {
                                    offset_y1 += 0.01;
                                }
                                else if (3 < radius_edge && radius_edge <= 4)
                                {
                                    offset_y1 += 0.02;
                                }
                                else if (4 < radius_edge && radius_edge <= 5)
                                {
                                    offset_y1 += 0.03;
                                }

                                相机1左偏移 = new double[] { offset_x1, offset_y1, radius_edge };
                                相机1右偏移 = new double[] { offset_x2, offset_y2, radius2 };

                                if (相机1右偏移[2] < -150)
                                {
                                    相机1右偏移[2] += 180;

                                }
                                else if (相机1右偏移[2] > 150)
                                {
                                    相机1右偏移[2] -= 180;
                                }

                                //吸螺母放料位置1[0] += OffsetToPulse(相机1左偏移[0]);
                                //吸螺母放料位置1[1] += OffsetToPulse(相机1左偏移[1]);
                                吸螺母放料位置1[2] -= 角度转换上螺母脉冲(相机1左偏移[2]);

                                //吸螺母放料位置2[0] += OffsetToPulse(相机1右偏移[0]);
                                //吸螺母放料位置2[1] += OffsetToPulse(相机1右偏移[1]);
                                吸螺母放料位置2[2] -= 角度转换上螺母脉冲(相机1右偏移[2]);



                                string camera_data =
                                    //DateTime.Now + "," + "上螺母相机1第一次左轮廓" + "," + string.Join(",", 相机1左轮廓) + "\n" +
                                    DateTime.Now + "," + "上螺母相机1第一次1左圆" + "," + string.Join(",", 相机1左圆) + "\n" +
                                    DateTime.Now + "," + "上螺母相机1第一次1右轮廓" + "," + string.Join(",", 相机1右轮廓) + "\n" +
                                    DateTime.Now + "," + "上螺母相机1第一次1右圆" + "," + string.Join(",", 相机1右圆) + "\n" +
                                    DateTime.Now + "," + "测试左偏移" + "," + string.Join(",", 相机1左偏移) + "\n" +
                                    //DateTime.Now + "," + "上螺母相机1左边缘角度偏移" + "," + string.Join(",", radius_edge) + "\n" +
                                    DateTime.Now + "," + "测试右偏移" + "," + string.Join(",", 相机1右偏移);
                                camera_log_file.WriteLine(camera_data);


                                Log.Write("上螺母相机1第一次左螺母偏移:" + string.Join(",", 相机1左偏移));
                                Log.Write("上螺母相机1第一次右螺母偏移:" + string.Join(",", 相机1右偏移));
                                
                                
                            }
                            else
                            {
                                Log.Write("吸螺母下相机一次定位结果获取失败");
                                //GLOBAL.plc.WriteDword(GLOBAL.config.Get("吸螺母X轴放料位置1_register"), 吸螺母抛料位置[0]);
                                //GLOBAL.plc.WriteDword(GLOBAL.config.Get("吸螺母Y轴放料位置1_register"), 吸螺母抛料位置[1]);
                                //GLOBAL.plc.WriteDword(GLOBAL.config.Get("吸螺母X轴放料位置2_register"), 吸螺母抛料位置[0]);
                                //GLOBAL.plc.WriteDword(GLOBAL.config.Get("吸螺母Y轴放料位置2_register"), 吸螺母抛料位置[1]);
                                ////出错抛料,回环线不会运动
                                //GLOBAL.plc.WriteMBit(GLOBAL.config.Get("吸螺母下相机拍照失败_register"), "1");

                                //GLOBAL.plc.WriteMBit(GLOBAL.config.Get("吸螺母下相机拍照完成_register"), "1");
                                //Thread.Sleep(500);
                                has_wrong = true;
                            }
                            //写入偏移
                            GLOBAL.plc.WriteDword(GLOBAL.config.Get("吸螺母W1轴第二次拍照位置_register"), 吸螺母放料位置1[2], 角度转换上螺母脉冲系数);
                            GLOBAL.plc.WriteDword(GLOBAL.config.Get("吸螺母W2轴第二次拍照位置_register"), 吸螺母放料位置2[2], 角度转换上螺母脉冲系数);


                            //写入第一次完成标志
                            GLOBAL.plc.WriteMBit(GLOBAL.config.Get("吸螺母下相机拍照完成_register"), "1");
                            //Thread.Sleep(interval);
                            //取消复位
                            //GLOBAL.plc.WriteMBit(GLOBAL.config.Get("吸螺母下相机拍照完成_register"), "0");

                            //等待plc动作和相机拍照完成
                            吸螺母到达二次拍照位置 = "0";
                            
                            while (吸螺母到达二次拍照位置 != "1" && GLOBAL.plc.IsConnect && GLOBAL.cameras.IsConnect && GLOBAL.运行标志 == "1")
                            {
                                
                                GLOBAL.plc.ReadMBit(GLOBAL.config.Get("吸螺母到达二次拍照位置_register"), ref 吸螺母到达二次拍照位置);
                                Thread.Sleep(interval);
                            }
                            //Thread.Sleep(interval);
                            //临时延时
                            Thread.Sleep(debug_delay);
                            Result  r2 = GLOBAL.cameras.GetTaskStatus(1);
                            Log.Write("相机1第二次:" + r2.ToString());

                            //第二次拍照
                            if (r2 == Result.Passed)
                            {
                                //string[] 相机1左轮廓 = GLOBAL.cameras.GetContourResult(Camera.Address[1], 111);
                                string[] 相机1左圆 = GLOBAL.cameras.GetCircleResult(
                                       Camera.AddressOffset(
                                        Camera.Address[1],
                                        (int)圆1["起始地址"]),
                                       (int)圆1["长度"]);
                                string[] 相机1右圆 = GLOBAL.cameras.GetCircleResult(
                                        Camera.AddressOffset(
                                        Camera.Address[1],
                                        (int)圆2["起始地址"]),
                                        (int)圆2["长度"]);
                                string[] 相机1右轮廓 = GLOBAL.cameras.GetContourResult(
                                        Camera.AddressOffset(
                                        Camera.Address[1],
                                        (int)轮廓["起始地址"]),
                                        (int)轮廓["长度"]);
                                string[] 相机1边缘 = GLOBAL.cameras.GetEdgeResult(
                                        Camera.AddressOffset(
                                        Camera.Address[1],
                                        (int)边缘["起始地址"]),
                                        (int)边缘["长度"]);
                                //string[] 相机1左圆 = GLOBAL.cameras.GetCircleResult(Camera.AddressOffset(Camera.Address[1], 224), 15);
                                //string[] 相机1右轮廓 = GLOBAL.cameras.GetContourResult(Camera.AddressOffset(Camera.Address[1], 112), 111);
                                //string[] 相机1右圆 = GLOBAL.cameras.GetCircleResult(Camera.AddressOffset(Camera.Address[1], 239), 15);
                                //string[] 相机1边缘 = GLOBAL.cameras.GetEdgeResult(Camera.AddressOffset(Camera.Address[1], 254), 16);
                                double[] 相机1左偏移 = { 0, 0, 0 };
                                double[] 相机1右偏移 = { 0, 0, 0 };

                                //偏移量计算
                                double offset_x1 = 圆1基准点[0] - Convert.ToDouble(相机1左圆[0]);
                                double offset_y1 = 圆1基准点[1] - Convert.ToDouble(相机1左圆[1]);
                                //double radius1 = 轮廓匹配1基准点[2] - Convert.ToDouble(相机1左轮廓[3]);
                                double offset_x2 = 圆2基准点[0] - Convert.ToDouble(相机1右圆[0]);
                                double offset_y2 = 圆2基准点[1] - Convert.ToDouble(相机1右圆[1]);
                                double radius2 = 轮廓匹配2基准点[2] - Convert.ToDouble(相机1右轮廓[3]);
                                double radius_edge = 相机1边缘基准角度 - Convert.ToDouble(相机1边缘[0]);

                                相机1左偏移 = new double[] { offset_x1, offset_y1, radius_edge };
                                相机1右偏移 = new double[] { offset_x2, offset_y2, radius2 };

                                吸螺母放料位置1[0] += OffsetToPulse(相机1左偏移[0]);
                                吸螺母放料位置1[1] += OffsetToPulse(相机1左偏移[1]);
                                //吸螺母放料位置1[2] += RadiusToPulse(相机1左偏移[2]);

                                吸螺母放料位置2[0] += OffsetToPulse(相机1右偏移[0]);
                                吸螺母放料位置2[1] += OffsetToPulse(相机1右偏移[1]);
                                //吸螺母放料位置2[2] += RadiusToPulse(相机1右偏移[2]);

                                string camera_data =
                                    //DateTime.Now + "," + "上螺母相机1第二次左轮廓" + "," + string.Join(",", 相机1左轮廓) + "\n" +
                                    DateTime.Now + "," + "上螺母相机1第二次左圆" + "," + string.Join(",", 相机1左圆) + "\n" +
                                    DateTime.Now + "," + "上螺母相机1第二次右轮廓" + "," + string.Join(",", 相机1右轮廓) + "\n" +
                                    DateTime.Now + "," + "上螺母相机1第二次右圆" + "," + string.Join(",", 相机1右圆) + "\n" +
                                    DateTime.Now + "," + "上螺母相机1第二次左螺母偏移" + "," + string.Join(",", 相机1左偏移) + "\n" +
                                  //DateTime.Now + "," + "上螺母相机1第二次左边缘角度偏移" + "," + string.Join(",", radius_edge) + "\n" +
                                    DateTime.Now + "," + "上螺母相机1第二次右螺母偏移" + "," + string.Join(",", 相机1右偏移);
                                camera_log_file.WriteLine(camera_data);

                                if (Math.Abs(相机1左偏移[2])>2|| (Math.Abs(相机1右偏移[2])>3&&Math.Abs(相机1右偏移[2]) < 178))
                                {
                                    Log.Write("螺母角度矫正失败");
                                    has_wrong = true;
                                }

                                Log.Write("上螺母相机1第二次左螺母偏移:" + string.Join(",", 相机1左偏移));
                                Log.Write("上螺母相机1第二次右螺母偏移:" + string.Join(",", 相机1右偏移));

                            }
                            else
                            {
                                Log.Write("吸螺母下相机二次定位结果获取失败");

                                //GLOBAL.plc.WriteDword(GLOBAL.config.Get("吸螺母X轴放料位置1_register"), 吸螺母抛料位置[0]);
                                //GLOBAL.plc.WriteDword(GLOBAL.config.Get("吸螺母Y轴放料位置1_register"), 吸螺母抛料位置[1]);
                                //GLOBAL.plc.WriteDword(GLOBAL.config.Get("吸螺母X轴放料位置2_register"), 吸螺母抛料位置[0]);
                                //GLOBAL.plc.WriteDword(GLOBAL.config.Get("吸螺母Y轴放料位置2_register"), 吸螺母抛料位置[1]);
                                ////出错抛料,回环线不会运动
                                //GLOBAL.plc.WriteMBit(GLOBAL.config.Get("吸螺母下相机拍照失败_register"), "1");
                                //Thread.Sleep(500);
                                has_wrong = true;
                            }

                            GLOBAL.plc.WriteDword(GLOBAL.config.Get("吸螺母X轴放料位置1_register"), 吸螺母放料位置1[0]);
                            GLOBAL.plc.WriteDword(GLOBAL.config.Get("吸螺母Y轴放料位置1_register"), 吸螺母放料位置1[1]);
                            GLOBAL.plc.WriteDword(GLOBAL.config.Get("吸螺母W轴放料位置1_register"), 吸螺母放料位置1[2], 角度转换上螺母脉冲系数);
                            GLOBAL.plc.WriteDword(GLOBAL.config.Get("吸螺母X轴放料位置2_register"), 吸螺母放料位置2[0]);
                            GLOBAL.plc.WriteDword(GLOBAL.config.Get("吸螺母Y轴放料位置2_register"), 吸螺母放料位置2[1]);
                            GLOBAL.plc.WriteDword(GLOBAL.config.Get("吸螺母W轴放料位置2_register"), 吸螺母放料位置2[2], 角度转换上螺母脉冲系数);


                            //切换到空任务
                            GLOBAL.cameras.SelectTask(1, (int)GLOBAL.config.configs["相机参数"]["空模板"]["相机1"]);
                            //切换任务
                            GLOBAL.cameras.SelectTask(1, (int)GLOBAL.config.configs["相机参数"]["默认模板"]["相机1"]);

                            //写入第二次完成标志
                            GLOBAL.plc.WriteMBit(GLOBAL.config.Get("吸螺母下相机第二次拍照完成_register"), "1");
                            Thread.Sleep(interval);
                            // GLOBAL.plc.WriteMBit(GLOBAL.config.Get("吸螺母下相机第二次拍照完成_register"), "0");

                            //等待plc动作和相机拍照完成
                            相机1触发 = "0";
                            while (相机1触发 != "1" && GLOBAL.plc.IsConnect && GLOBAL.cameras.IsConnect && GLOBAL.运行标志 == "1")
                            {
                                
                                GLOBAL.plc.ReadMBit(GLOBAL.config.Get("相机1触发_register"), ref 相机1触发);
                                Thread.Sleep(interval);
                            }
                            //Thread.Sleep(interval);
                            //临时延时

                            r1 = Result.None;
                            for (int i = 0; i < max_wait; i++)
                            {
                                r1 = GLOBAL.cameras.GetTaskStatus(0);
                                if (r1 != Result.None)
                                    break;
                                Thread.Sleep(interval);
                            }
                            Result result_status1 = Result.None;
                            string[] 相机0Blob = GLOBAL.cameras.GetStatusBlobResult(Camera.AddressOffset(
                                                                                                                            Camera.Address[0],
                                                                                                                            (int)blob["起始地址"]),
                                                                                                                        (int)blob["长度"], ref result_status1 );

                            // Result result_status2 = Result.None;
                            // Result result_status3 = Result.None;
                            //Thread.Sleep(debug_delay);
                            //string[] 相机0Blob = GLOBAL.cameras.GetStatusBlobResult(Camera.Address[0], 64, ref result_status1);

                            /* string[] 相机0Blob2 = GLOBAL.cameras.GetStatusBlobResult(Camera.AddressOffset(Camera.Address[0], 208), 64,ref result_status2);
                             string[] 相机0Blob3 = GLOBAL.cameras.GetStatusBlobResult(Camera.AddressOffset(Camera.Address[0], 416), 64,ref result_status3);
                             Log.Write("相机0Blob2:" + result_status2);
                             Log.Write("相机0Blob3:" + result_status3);

                             if (result_status2 == Result.Passed && result_status3 == Result.Passed)
                             {
                                 GLOBAL.plc.WriteMBit(GLOBAL.config.Get("螺母检测有无_register"), "1");
                             }
                             else
                             {
                                 GLOBAL.plc.WriteMBit(GLOBAL.config.Get("螺母检测有无_register"), "0");
                             }
                             */
                            // r1 = GLOBAL.cameras.GetTaskStatus(0);
                            Log.Write("相机0:" + r1);
                            Log.Write("相机0结果状态:" + result_status1);
                            //上螺母上相机
                            if (result_status1 == Result.Passed)
                            {
                                double[] Blob基准点 = blob["基准点"].ToArray().Select(x => (double)x).ToArray();
                                //第一次拍照
                                // string[] 相机0目标定位器 = GLOBAL.cameras.GetObjectResult(Camera.Address[0], 16);
                              

                                double offset_x = Blob基准点[0] - Convert.ToDouble(相机0Blob[1]);
                                double offset_y = Blob基准点[1] - Convert.ToDouble(相机0Blob[2]);
                                double radius = 0;
                                double[] 相机0偏移 = { 0, 0, 0 };
                                ///double[] d_相机0目标定位器 = 相机0目标定位器.Select(x => Convert.ToDouble(x)).ToArray();
                                //  double[] d_相机0Blob = 相机0Blob.Select(x => Convert.ToDouble(x)).ToArray();
                                // radius = d_相机0目标定位器[3];
                                //180 * ATAN((x2- x1) / (y2 - y1)) / PI()

                                /*
                                double center_x = 目标定位器准点[0] - d_相机0目标定位器[0];
                                double center_y = 目标定位器准点[1] - d_相机0目标定位器[1];
                                */
                                相机0偏移[0] = offset_x;
                                相机0偏移[1] = offset_y;
                                //相机0偏移[2] = 0 - radius;

                                吸螺母放料位置1[0] -= OffsetToPulse(相机0偏移[0]);
                                吸螺母放料位置1[1] -= OffsetToPulse(相机0偏移[1]);
                                //吸螺母放料位置1[2] += RadiusToPulse(相机1左偏移[2]);

                                吸螺母放料位置2[0] -= OffsetToPulse(相机0偏移[0]);
                                吸螺母放料位置2[1] -= OffsetToPulse(相机0偏移[1]);
                                //吸螺母放料位置2[2] += RadiusToPulse(相机1右偏移[2]);

                                string camera_data =
                                    // "相机0目标定位器" + "," + string.Join(",", 相机0目标定位器) + "\n" +
                                    DateTime.Now + "," + "上螺母相机0Blob" + "," + string.Join(",", 相机0Blob) + "\n" +
                                    DateTime.Now + "," + "上螺母相机0偏移" + "," + string.Join(",", 相机0偏移);
                                camera_log_file.WriteLine(camera_data);

                                //暂时不给料盘偏移

                                GLOBAL.plc.WriteDword(GLOBAL.config.Get("吸螺母X轴放料位置1_register"), 吸螺母放料位置1[0]);
                                GLOBAL.plc.WriteDword(GLOBAL.config.Get("吸螺母Y轴放料位置1_register"), 吸螺母放料位置1[1]);
                                //GLOBAL.plc.WriteDword(GLOBAL.config.Get("吸螺母W轴放料位置1_register"), 吸螺母放料位置1[2]);
                                GLOBAL.plc.WriteDword(GLOBAL.config.Get("吸螺母X轴放料位置2_register"), 吸螺母放料位置2[0]);
                                GLOBAL.plc.WriteDword(GLOBAL.config.Get("吸螺母Y轴放料位置2_register"), 吸螺母放料位置2[1]);
                                //GLOBAL.plc.WriteDword(GLOBAL.config.Get("吸螺母W轴放料位置2_register"), 吸螺母放料位置2[2]);

                                Log.Write("放螺母料盘偏移:" + string.Join(",", 相机0偏移));

                            }
                            else
                            {
                                Log.Write("吸螺母上相机定位结果获取失败");
                                has_wrong = true;
                            }

                            //切换到空任务
                            GLOBAL.cameras.SelectTask(0, (int)GLOBAL.config.configs["相机参数"]["空模板"]["相机0"]);
                            //切换任务
                            GLOBAL.cameras.SelectTask(0, (int)GLOBAL.config.configs["相机参数"]["默认模板"]["相机0"]);

                            if (has_wrong)
                            {
                                螺母连续_NG++;

                                if (螺母连续_NG >= 3)
                                {
                                    GLOBAL.plc.WriteMBit(GLOBAL.config.Get("螺母拍照失败报警_register"), "1");
                                    螺母连续_NG = 0;
                                }
                                Log.Write("螺母定位失败抛料");
                                //螺母_NG++;
                                GLOBAL.plc.WriteDword(GLOBAL.config.Get("吸螺母X轴放料位置1_register"), 吸螺母抛料位置[0]);
                                GLOBAL.plc.WriteDword(GLOBAL.config.Get("吸螺母Y轴放料位置1_register"), 吸螺母抛料位置[1]);
                                GLOBAL.plc.WriteDword(GLOBAL.config.Get("吸螺母X轴放料位置2_register"), 吸螺母抛料位置[0]);
                                GLOBAL.plc.WriteDword(GLOBAL.config.Get("吸螺母Y轴放料位置2_register"), 吸螺母抛料位置[1]);
                                //出错抛料,回环线不会运动
                                GLOBAL.plc.WriteMBit(GLOBAL.config.Get("吸螺母下相机拍照失败_register"), "1");
                            }
                            else
                            {
                                //改变当前吸螺母工位的螺母状态
                                GLOBAL.station[2].Tray.有大螺母 = true;
                                GLOBAL.station[2].Tray.有小螺母 = true;
                                螺母连续_NG = 0;
                                GLOBAL.plc.WriteMBit(GLOBAL.config.Get("吸螺母下相机拍照失败_register"), "0");
                            }

                            GLOBAL.plc.WriteMBit(GLOBAL.config.Get("吸螺母上相机拍照完成_register"), "1");
                            Thread.Sleep(interval);
                            //取消复位
                            //GLOBAL.plc.WriteMBit(GLOBAL.config.Get("吸螺母上相机拍照完成_register"), "0");



                            Log.Write("吸螺母放料位置1:" + string.Join(",", 吸螺母放料位置1));
                            Log.Write("吸螺母放料位置2:" + string.Join(",", 吸螺母放料位置2));
                            Thread.Sleep(500);


                        }
                        else if (相机1触发 == "1")
                        {
                            Thread.Sleep(debug_delay);

                            int[] 吸螺母抛料位置 = GLOBAL.config.configs["相机参数"]["吸螺母抛料位置"].ToArray().Select(x => (int)(double)x).ToArray();
                            var 相机0模板0参数 = GLOBAL.config.configs["相机参数"]["相机0"]["模板0"];
                            var blob = 相机0模板0参数["blob"];
                            //上相机拍照
                            Result r0 = GLOBAL.cameras.GetTaskStatus(0);
                            Result result_status1 = Result.None;
                            string[] 相机0Blob = GLOBAL.cameras.GetStatusBlobResult(Camera.AddressOffset(
                                                                                                                            Camera.Address[0],
                                                                                                                            (int)blob["起始地址"]),
                                                                                                                        (int)blob["长度"], ref result_status1);

                            //Log.Write("出错相机0:" + r0.ToString());
                            Log.Write("出错相机0:" + r0);
                            Log.Write("出错相机0结果状态:" + result_status1);
                            //上螺母上相机
                            if (result_status1 == Result.Passed)
                            {
                                double[] Blob基准点 = blob["基准点"].ToArray().Select(x => (double)x).ToArray();
                                //double[] Blob基准点 = 相机0模板0参数["Blob基准点"].ToArray().Select(x => (double)x).ToArray();
                                //第一次拍照
                                // string[] 相机0目标定位器 = GLOBAL.cameras.GetObjectResult(Camera.Address[0], 16);
                                //string[] 相机0Blob = GLOBAL.cameras.GetBlobResult(Camera.Address[0], 64);

                                double offset_x = Blob基准点[0] - Convert.ToDouble(相机0Blob[0]);
                                double offset_y = Blob基准点[1] - Convert.ToDouble(相机0Blob[1]);
                                double radius = 0;
                                double[] 相机0偏移 = { 0, 0, 0 };
                                ///double[] d_相机0目标定位器 = 相机0目标定位器.Select(x => Convert.ToDouble(x)).ToArray();
                                //  double[] d_相机0Blob = 相机0Blob.Select(x => Convert.ToDouble(x)).ToArray();
                                // radius = d_相机0目标定位器[3];
                                //180 * ATAN((x2- x1) / (y2 - y1)) / PI()

                                /*
                                double center_x = 目标定位器准点[0] - d_相机0目标定位器[0];
                                double center_y = 目标定位器准点[1] - d_相机0目标定位器[1];
                                */
                                相机0偏移[0] = offset_x;
                                相机0偏移[1] = offset_y;
                                //相机0偏移[2] = 0 - radius;
                                

                                string camera_data =
                                    // "相机0目标定位器" + "," + string.Join(",", 相机0目标定位器) + "\n" +
                                    DateTime.Now + "," + "出错上螺母相机0Blob" + "," + string.Join(",", 相机0Blob) + "\n" +
                                    DateTime.Now + "," + "出错上螺母相机0偏移" + "," + string.Join(",", 相机0偏移);
                                camera_log_file.WriteLine(camera_data);


                                Log.Write("出错放螺母料盘偏移:" + string.Join(",", 相机0偏移));
                                
                            }

                            Log.Write("螺母定位失败抛料");

                            GLOBAL.plc.WriteDword(GLOBAL.config.Get("吸螺母X轴放料位置1_register"), 吸螺母抛料位置[0]);
                            GLOBAL.plc.WriteDword(GLOBAL.config.Get("吸螺母Y轴放料位置1_register"), 吸螺母抛料位置[1]);
                            GLOBAL.plc.WriteDword(GLOBAL.config.Get("吸螺母X轴放料位置2_register"), 吸螺母抛料位置[0]);
                            GLOBAL.plc.WriteDword(GLOBAL.config.Get("吸螺母Y轴放料位置2_register"), 吸螺母抛料位置[1]);

                            //切换到空任务
                            GLOBAL.cameras.SelectTask(0, (int)GLOBAL.config.configs["相机参数"]["空模板"]["相机0"]);
                            //切换任务
                            GLOBAL.cameras.SelectTask(0, (int)GLOBAL.config.configs["相机参数"]["默认模板"]["相机0"]);
                            //出错抛料,回环线不会运动
                            GLOBAL.plc.WriteMBit(GLOBAL.config.Get("吸螺母下相机拍照失败_register"), "1");

                            GLOBAL.plc.WriteMBit(GLOBAL.config.Get("吸螺母上相机拍照完成_register"), "1");
                            Thread.Sleep(interval);
                            //取消复位
                            //GLOBAL.plc.WriteMBit(GLOBAL.config.Get("吸螺母上相机拍照完成_register"), "0");
                            
                            Thread.Sleep(500);
                        }
                        else if (吸螺母到达二次拍照位置 == "1")//出错处理
                        {
                            int[] 吸螺母放料位置1 = GLOBAL.config.configs["相机参数"]["吸螺母放料位置1"].ToArray().Select(x => (int)(double)x).ToArray();
                            int[] 吸螺母放料位置2 = GLOBAL.config.configs["相机参数"]["吸螺母放料位置2"].ToArray().Select(x => (int)(double)x).ToArray();

                            int[] 吸螺母抛料位置 = GLOBAL.config.configs["相机参数"]["吸螺母抛料位置"].ToArray().Select(x => (int)(double)x).ToArray();

                            var 相机1模板2参数 = GLOBAL.config.configs["相机参数"]["相机1"]["模板2"];
                            var 圆1 = 相机1模板2参数["圆1"];
                            var 圆2 = 相机1模板2参数["圆2"];
                            var 轮廓 = 相机1模板2参数["轮廓"];
                            var 边缘 = 相机1模板2参数["边缘"];
                            var 圆1基准点 = 圆1["基准点"].ToArray().Select(x => (double)x).ToArray();
                            var 圆2基准点 = 圆2["基准点"].ToArray().Select(x => (double)x).ToArray();
                            //var 轮廓匹配1基准点 = 相机1模板2参数["轮廓匹配1基准点"].ToArray().Select(x => (double)x).ToArray();
                            var 轮廓匹配2基准点 = 轮廓["基准点"].ToArray().Select(x => (double)x).ToArray();
                            double 相机1边缘基准角度 = (double)边缘["基准角度"];
                            Thread.Sleep(debug_delay);
                            Result r1 = GLOBAL.cameras.GetTaskStatus(1);
                            Log.Write("出错相机1第二次:" + r1.ToString());

                            //第二次拍照
                            if (r1 == Result.Passed)
                            {
                                //string[] 相机1左轮廓 = GLOBAL.cameras.GetContourResult(Camera.Address[1], 111);
                                string[] 相机1左圆 = GLOBAL.cameras.GetCircleResult(
                                       Camera.AddressOffset(
                                        Camera.Address[1],
                                        (int)圆1["起始地址"]),
                                       (int)圆1["长度"]);
                                string[] 相机1右圆 = GLOBAL.cameras.GetCircleResult(
                                        Camera.AddressOffset(
                                        Camera.Address[1],
                                        (int)圆2["起始地址"]),
                                        (int)圆2["长度"]);
                                string[] 相机1右轮廓 = GLOBAL.cameras.GetContourResult(
                                        Camera.AddressOffset(
                                        Camera.Address[1],
                                        (int)轮廓["起始地址"]),
                                        (int)轮廓["长度"]);
                                string[] 相机1边缘 = GLOBAL.cameras.GetEdgeResult(
                                        Camera.AddressOffset(
                                        Camera.Address[1],
                                        (int)边缘["起始地址"]),
                                        (int)边缘["长度"]);
                                //string[] 相机1左圆 = GLOBAL.cameras.GetCircleResult(Camera.AddressOffset(Camera.Address[1], 224), 15);
                                //string[] 相机1右轮廓 = GLOBAL.cameras.GetContourResult(Camera.AddressOffset(Camera.Address[1], 112), 111);
                                //string[] 相机1右圆 = GLOBAL.cameras.GetCircleResult(Camera.AddressOffset(Camera.Address[1], 239), 15);
                                //string[] 相机1边缘 = GLOBAL.cameras.GetEdgeResult(Camera.AddressOffset(Camera.Address[1], 254), 16);
                                double[] 相机1左偏移 = { 0, 0, 0 };
                                double[] 相机1右偏移 = { 0, 0, 0 };

                                //偏移量计算
                                double offset_x1 = 圆1基准点[0] - Convert.ToDouble(相机1左圆[0]);
                                double offset_y1 = 圆1基准点[1] - Convert.ToDouble(相机1左圆[1]);
                                //double radius1 = 轮廓匹配1基准点[2] - Convert.ToDouble(相机1左轮廓[3]);
                                double offset_x2 = 圆2基准点[0] - Convert.ToDouble(相机1右圆[0]);
                                double offset_y2 = 圆2基准点[1] - Convert.ToDouble(相机1右圆[1]);
                                double radius2 = 轮廓匹配2基准点[2] - Convert.ToDouble(相机1右轮廓[3]);
                                double radius_edge = 相机1边缘基准角度 - Convert.ToDouble(相机1边缘[0]);

                                相机1左偏移 = new double[] { offset_x1, offset_y1, radius_edge };
                                相机1右偏移 = new double[] { offset_x2, offset_y2, radius2 };

                                吸螺母放料位置1[0] += OffsetToPulse(相机1左偏移[0]);
                                吸螺母放料位置1[1] += OffsetToPulse(相机1左偏移[1]);
                                //吸螺母放料位置1[2] += RadiusToPulse(相机1左偏移[2]);

                                吸螺母放料位置2[0] += OffsetToPulse(相机1右偏移[0]);
                                吸螺母放料位置2[1] += OffsetToPulse(相机1右偏移[1]);
                                //吸螺母放料位置2[2] += RadiusToPulse(相机1右偏移[2]);

                                string camera_data =
                                    //DateTime.Now + "," + "出错上螺母相机1第二次左轮廓" + "," + string.Join(",", 相机1左轮廓) + "\n" +
                                    DateTime.Now + "," + "出错上螺母相机1第二次左圆" + "," + string.Join(",", 相机1左圆) + "\n" +
                                    DateTime.Now + "," + "出错上螺母相机1第二次右轮廓" + "," + string.Join(",", 相机1右轮廓) + "\n" +
                                    DateTime.Now + "," + "出错上螺母相机1第二次右圆" + "," + string.Join(",", 相机1右圆) + "\n" +
                                    DateTime.Now + "," + "出错上螺母相机1第二次左螺母偏移" + "," + string.Join(",", 相机1左偏移) + "\n" +
                                    DateTime.Now + "," + "出错上螺母相机1第二次右螺母偏移" + "," + string.Join(",", 相机1右偏移);
                                camera_log_file.WriteLine(camera_data);


                                Log.Write("出错上螺母相机1第二次左螺母偏移:" + string.Join(",", 相机1左偏移));
                                Log.Write("出错上螺母相机1第二次右螺母偏移:" + string.Join(",", 相机1右偏移));

                            }

                            Log.Write("螺母定位失败抛料");

                            GLOBAL.plc.WriteDword(GLOBAL.config.Get("吸螺母X轴放料位置1_register"), 吸螺母抛料位置[0]);
                            GLOBAL.plc.WriteDword(GLOBAL.config.Get("吸螺母Y轴放料位置1_register"), 吸螺母抛料位置[1]);
                            GLOBAL.plc.WriteDword(GLOBAL.config.Get("吸螺母X轴放料位置2_register"), 吸螺母抛料位置[0]);
                            GLOBAL.plc.WriteDword(GLOBAL.config.Get("吸螺母Y轴放料位置2_register"), 吸螺母抛料位置[1]);

                            //切换到空任务
                            GLOBAL.cameras.SelectTask(1, (int)GLOBAL.config.configs["相机参数"]["空模板"]["相机1"]);
                            //切换任务
                            GLOBAL.cameras.SelectTask(1, (int)GLOBAL.config.configs["相机参数"]["默认模板"]["相机1"]);
                            //写入第二次完成标志
                            GLOBAL.plc.WriteMBit(GLOBAL.config.Get("吸螺母下相机第二次拍照完成_register"), "1");
                            Thread.Sleep(interval);
                            //取消复位
                            //GLOBAL.plc.WriteMBit(GLOBAL.config.Get("吸螺母下相机第二次拍照完成_register"), "0");

                            //Thread.Sleep(interval);

                            Log.Write("出错吸螺母放料位置1:" + string.Join(",", 吸螺母放料位置1));
                            Log.Write("出错吸螺母放料位置2:" + string.Join(",", 吸螺母放料位置2));
                        }
                    }

                }
                catch (Exception e)
                {
                    Log.Write(e.ToString());
                }
                Thread.Sleep(interval);
            }
        }
        /// <summary>
        /// 实际使用相机5,6
        /// </summary>
        private void 上屏蔽片触发方法()
        {
            while (loop)
            {
                try
                {
                    //goto到的地方
                    //上屏蔽片:
                    if (GLOBAL.plc.IsConnect && GLOBAL.cameras.IsConnect && GLOBAL.运行标志 == "1" && GLOBAL.总警告 == "0")
                    {
                        string 相机6触发 = "0";//上屏蔽片上相机
                        string 吸屏蔽片到达二次拍照位置 = "0";//上屏蔽片上相机
                        string 相机7触发 = "0";//上屏蔽片下相机

                        GLOBAL.plc.ReadMBit(GLOBAL.config.Get("相机6触发_register"), ref 相机6触发);
                        GLOBAL.plc.ReadMBit(GLOBAL.config.Get("吸屏蔽片到达二次拍照位置_register"), ref 吸屏蔽片到达二次拍照位置);
                        GLOBAL.plc.ReadMBit(GLOBAL.config.Get("相机7触发_register"), ref 相机7触发);
                        if (相机7触发 == "1")
                        {
                            bool has_wrong = false;
                            //第一次拍照
                            var 相机6模板0参数 = GLOBAL.config.configs["相机参数"]["相机6"]["模板0"];
                            var blob1 = 相机6模板0参数["blob1"];
                            var blob2 = 相机6模板0参数["blob2"];
                            double[] Blob1基准点 = blob1["基准点"].ToArray().Select(x => (double)x).ToArray();
                            double[] Blob2基准点 = blob2["基准点"].ToArray().Select(x => (double)x).ToArray();
                            //double 相机6Blob角度 = (double)相机6模板0参数["Blob角度"];
                            double 相机6Blob角度 = 180 * Math.Atan(
                                    (Blob2基准点[0] - Blob1基准点[0])
                                    / (Blob2基准点[1] - Blob1基准点[1]))
                                    / Math.PI;
                            double 屏蔽片斜率 = (double)相机6模板0参数["屏蔽片斜率"];
                            //double 边缘基准角度 = (double)相机6模板0参数["边缘基准角度"];
                            int[] 吸屏蔽片放料位置 = GLOBAL.config.configs["相机参数"]["吸屏蔽片放料位置"].ToArray().Select(x => (int)(double)x).ToArray();

                            int[] 吸屏蔽片抛料位置 = GLOBAL.config.configs["相机参数"]["吸屏蔽片抛料位置"].ToArray().Select(x => (int)(double)x).ToArray();
                            //int[] 吸屏蔽片放料位置 = GLOBAL.config.Get("pingbipian_position").Split(',').Select(x => Convert.ToInt32(x)).ToArray();

                            //调试延时
                            //Thread.Sleep(500);
                            //Thread.Sleep(interval);
                            Result r1 = Result.None;
                            for (int i = 0; i < max_wait; i++)
                            {
                                r1 = GLOBAL.cameras.GetTaskStatus(6);
                                if (r1 != Result.None)
                                    break;
                                Thread.Sleep(interval);

                            }
                           // Result r1 = GLOBAL.cameras.GetTaskStatus(6);
                            Log.Write("相机6第一次:" + r1.ToString());
                            double temp = 0;
                            
                            if (r1 == Result.Passed)
                            {
                                //第一次拍照
                                string[] 相机6Blob1 = GLOBAL.cameras.GetBlobResult(
                                               Camera.AddressOffset(
                                                Camera.Address[6],
                                                (int)blob1["起始地址"]),
                                               (int)blob1["长度"]);
                                string[] 相机6Blob2 = GLOBAL.cameras.GetBlobResult(
                                               Camera.AddressOffset(
                                                Camera.Address[6],
                                                (int)blob2["起始地址"]),
                                               (int)blob2["长度"]);
                                //  string[] 相机6Blob1 = GLOBAL.cameras.GetBlobResult(Camera.Address[6], 64);
                                // string[] 相机6Blob2 = GLOBAL.cameras.GetBlobResult(Camera.AddressOffset(Camera.Address[6], 208), 64);
                                //string[] 相机6边缘 = GLOBAL.cameras.GetEdgeResult(Camera.AddressOffset(Camera.Address[6], 416), 11);

                                double radius = 0;
                                double[] 相机6偏移 = { 0, 0, 0 };
                                double[] d_Blob定位器1 = 相机6Blob1.Select(x => Convert.ToDouble(x)).ToArray();
                                double[] d_Blob定位器2 = 相机6Blob2.Select(x => Convert.ToDouble(x)).ToArray();
                                //double[] d_边缘 = 相机6边缘.Select(x => Convert.ToDouble(x)).ToArray();

                                double blob_radius = 180 * Math.Atan(
                                    (d_Blob定位器2[0] - d_Blob定位器1[0])
                                    / (d_Blob定位器2[1] - d_Blob定位器1[1]))
                                    / Math.PI;
                                radius = blob_radius;
                                //radius = d_边缘[0];
                                //180 * ATAN((x2- x1) / (y2 - y1)) / PI()

                                //double offset_x = ((Blob1基准点[0] - d_Blob定位器1[0]) + (Blob2基准点[0] - d_Blob定位器2[0])) / 2;
                                //double offset_y = ((Blob1基准点[1] - d_Blob定位器1[1]) + (Blob2基准点[1] - d_Blob定位器2[1])) / 2;
                                double offset_x = Blob1基准点[0] - d_Blob定位器1[0];
                                double offset_y = Blob1基准点[1] - d_Blob定位器1[1];

                                相机6偏移[0] = offset_x;
                                相机6偏移[1] = offset_y;
                                //相机6偏移[2] = 边缘基准角度 - radius;
                                相机6偏移[2] = 相机6Blob角度 - radius;
                                //temp = 相机6偏移[2];
                                double 测试x偏移 = offset_x-(相机6偏移[2] / 屏蔽片斜率) ;
                                double 测试y偏移 = offset_y;

                                string camera_data =
                                    DateTime.Now + "," + "上屏蔽片相机6第一次Blob1" + "," + string.Join(",", 相机6Blob1) + "\n" +
                                    DateTime.Now + "," + "上屏蔽片相机6第一次Blob2" + "," + string.Join(",", 相机6Blob2) + "\n" +
                                    DateTime.Now + "," + "上屏蔽片相机6第一次Blob角度" + "," + blob_radius + "\n" +
                                    DateTime.Now + "," + "测试x偏移" + "," + 测试x偏移 + "\n" +
                                    DateTime.Now + "," + "测试y偏移" + "," + 测试y偏移 + "\n" +
                                    DateTime.Now + "," + "上屏蔽片相机6第一次偏移" + "," + string.Join(",", 相机6偏移);
                                camera_log_file.WriteLine(camera_data);


                                //此处插入料盘偏移计算,然后算出最终对基准位置偏移

                                //吸屏蔽片放料位置[0] += OffsetToPulse(相机6偏移[0]);
                                //吸屏蔽片放料位置[1] += OffsetToPulse(相机6偏移[1]);
                                吸屏蔽片放料位置[3] -= 角度转换上屏蔽片脉冲(相机6偏移[2]);


                                Log.Write("吸屏蔽片第一次拍照偏移:" + string.Join(",", 相机6偏移));


                                ///////////////////////////////////////修改位置//////////////////////////////
                                /*GLOBAL.plc.WriteMBit(GLOBAL.config.Get("吸螺母工位完成_register"), "1");
                                Thread.Sleep(interval);
                                GLOBAL.plc.WriteMBit(GLOBAL.config.Get("吸螺母工位完成_register"), "0");*/

                            }
                            else
                            {
                                Log.Write("上屏蔽片下相机一次定位结果获取失败");
                                has_wrong = true;
                                

                            }

                            //if (temp>4||r1!=Result.Passed)
                            //{
                            //    GLOBAL.plc.WriteMBit(GLOBAL.config.Get("吸屏蔽片失败重吸标志_register"),"1");
                            //}

                            //写入偏移
                            GLOBAL.plc.WriteDword(GLOBAL.config.Get("吸屏蔽片W轴第二次拍照位置_register"), 吸屏蔽片放料位置[3], 角度转换上屏蔽片脉冲系数);
                            //写入第一次完成标志
                            GLOBAL.plc.WriteMBit(GLOBAL.config.Get("吸屏蔽片下相机拍照完成_register"), "1");
                            //取消复位
                            Thread.Sleep(interval);
                            //GLOBAL.plc.WriteMBit(GLOBAL.config.Get("吸屏蔽片下相机拍照完成_register"), "0");

                            //等待plc动作和相机拍照完成
                            吸屏蔽片到达二次拍照位置 = "0";
                            //暂时不等信号
                            while (吸屏蔽片到达二次拍照位置 != "1" && GLOBAL.plc.IsConnect && GLOBAL.cameras.IsConnect && GLOBAL.运行标志 == "1")
                            {
                                GLOBAL.plc.ReadMBit(GLOBAL.config.Get("吸屏蔽片到达二次拍照位置_register"), ref 吸屏蔽片到达二次拍照位置);
                                Thread.Sleep(interval);
                            }
                            //Thread.Sleep(interval);
                            //临时延时
                            Thread.Sleep(debug_delay);
                            Result r2 = GLOBAL.cameras.GetTaskStatus(6);
                            Log.Write("相机6第二次:" + r2.ToString());
                            if (r2 == Result.Passed)
                            {
                                //第二次拍照
                                string[] 相机6Blob1 = GLOBAL.cameras.GetBlobResult(
                                               Camera.AddressOffset(
                                                Camera.Address[6],
                                                (int)blob1["起始地址"]),
                                               (int)blob1["长度"]);
                                string[] 相机6Blob2 = GLOBAL.cameras.GetBlobResult(
                                               Camera.AddressOffset(
                                                Camera.Address[6],
                                                (int)blob2["起始地址"]),
                                               (int)blob2["长度"]);
                                //string[] 相机6边缘 = GLOBAL.cameras.GetEdgeResult(Camera.AddressOffset(Camera.Address[6], 416), 11);

                                double radius = 0;
                                double[] 相机6偏移 = { 0, 0, 0 };
                                double[] d_Blob定位器1 = 相机6Blob1.Select(x => Convert.ToDouble(x)).ToArray();
                                double[] d_Blob定位器2 = 相机6Blob2.Select(x => Convert.ToDouble(x)).ToArray();
                                //double[] d_边缘 = 相机6边缘.Select(x => Convert.ToDouble(x)).ToArray();

                                double blob_radius = 180 * Math.Atan(
                                    (d_Blob定位器2[0] - d_Blob定位器1[0])
                                    / (d_Blob定位器2[1] - d_Blob定位器1[1]))
                                    / Math.PI;
                                radius = blob_radius;
                                //radius = d_边缘[0];
                                //180 * ATAN((x2- x1) / (y2 - y1)) / PI()

                                //double offset_x = ((Blob1基准点[0] - d_Blob定位器1[0]) + (Blob2基准点[0] - d_Blob定位器2[0])) / 2;
                                // double offset_y = ((Blob1基准点[1] - d_Blob定位器1[1]) + (Blob2基准点[1] - d_Blob定位器2[1])) / 2;
                                double offset_x = Blob1基准点[0] - d_Blob定位器1[0];
                                double offset_y = Blob1基准点[1] - d_Blob定位器1[1];

                                相机6偏移[0] = offset_x;
                                相机6偏移[1] = offset_y;
                                //相机6偏移[2] = 边缘基准角度 - radius;
                                相机6偏移[2] = 相机6Blob角度 - radius;


                                string camera_data =
                                    DateTime.Now + "," + "上屏蔽片相机6第二次Blob1" + "," + string.Join(",", 相机6Blob1) + "\n" +
                                    DateTime.Now + "," + "上屏蔽片相机6第二次Blob2" + "," + string.Join(",", 相机6Blob2) + "\n" +
                                    DateTime.Now + "," + "上屏蔽片相机6第二次Blob角度" + "," + blob_radius + "\n" +
                                    //DateTime.Now + "," + "上屏蔽片相机6第二次边缘角度" + "," + radius + "\n" +
                                    DateTime.Now + "," + "上屏蔽片相机6第二次偏移" + "," + string.Join(",", 相机6偏移);
                                camera_log_file.WriteLine(camera_data);


                                //此处插入料盘偏移计算,然后算出最终对基准位置偏移

                                吸屏蔽片放料位置[0] += OffsetToPulse(相机6偏移[0]);
                                吸屏蔽片放料位置[1] += OffsetToPulse(相机6偏移[1]);
                                //吸屏蔽片放料位置[2] += 角度转换上屏蔽片脉冲(相机6偏移[2]);

                                Log.Write("吸屏蔽片第二次拍照偏移:" + string.Join(",", 相机6偏移));
                            }
                            else
                            {
                                Log.Write("上屏蔽片下相机二次定位结果获取失败");
                                has_wrong = true;
                            }


                            Log.Write("吸屏蔽片放料位置:" + string.Join(",", 吸屏蔽片放料位置));

                            GLOBAL.plc.WriteDword(GLOBAL.config.Get("吸屏蔽片X轴放料位置_register"), 吸屏蔽片放料位置[0]);
                            GLOBAL.plc.WriteDword(GLOBAL.config.Get("吸屏蔽片Y轴放料位置_register"), 吸屏蔽片放料位置[1]);
                            GLOBAL.plc.WriteDword(GLOBAL.config.Get("吸屏蔽片Z轴放料位置_register"), 吸屏蔽片放料位置[2]);
                            GLOBAL.plc.WriteDword(GLOBAL.config.Get("吸屏蔽片W轴放料位置_register"), 吸屏蔽片放料位置[3], 角度转换上屏蔽片脉冲系数);

                            //切换到空任务
                            GLOBAL.cameras.SelectTask(6, (int)GLOBAL.config.configs["相机参数"]["空模板"]["相机6"]);
                            // 切换任务                       
                            GLOBAL.cameras.SelectTask(6, (int)GLOBAL.config.configs["相机参数"]["默认模板"]["相机6"]);

                            GLOBAL.plc.WriteMBit(GLOBAL.config.Get("吸屏蔽片下相机第二次拍照完成_register"), "1");
                            //取消复位
                            Thread.Sleep(interval);
                            //GLOBAL.plc.WriteMBit(GLOBAL.config.Get("吸屏蔽片下相机第二次拍照完成_register"), "0");

                            //第三次拍照
                            //等待plc动作和相机拍照完成
                            相机6触发 = "0";
                            //暂时不等信号
                            while (相机6触发 != "1" && GLOBAL.plc.IsConnect && GLOBAL.cameras.IsConnect && GLOBAL.运行标志 == "1")
                            {
                                GLOBAL.plc.ReadMBit(GLOBAL.config.Get("相机6触发_register"), ref 相机6触发);
                                Thread.Sleep(interval);
                            }

                            //Thread.Sleep(debug_delay);
                            Result r3 = Result.None;
                            for (int i = 0; i < max_wait; i++)
                            {
                                r3 = GLOBAL.cameras.GetTaskStatus(5);
                                if (r3 != Result.None)
                                    break;
                                Thread.Sleep(interval);

                            }
                           // Result r3 = GLOBAL.cameras.GetTaskStatus(5);
                            Log.Write("相机5:" + r3.ToString());
                            if (r3 == Result.Passed)
                            {
                                var 相机5模板0参数 = GLOBAL.config.configs["相机参数"]["相机5"]["模板0"];
                                var 相机5blob1 = 相机5模板0参数["blob1"];
                                double[] Blob基准点1 = 相机5blob1["基准点"].ToArray().Select(x => (double)x).ToArray();
                                double[] Blob基准点2 = 相机5模板0参数["Blob2基准点"].ToArray().Select(x => (double)x).ToArray();
                                //double[] 圆基准点 = 相机5模板0参数["圆基准点"].ToArray().Select(x => (double)x).ToArray();
                                //double 相机5Blob角度 = (double)相机5模板0参数["Blob角度"];

                                double 相机5Blob角度 = 180 * Math.Atan(
                                        (Blob基准点2[0] - Blob基准点1[0])
                                        / (Blob基准点2[1] - Blob基准点1[1]))
                                        / Math.PI;
                                //第一次拍照
                                //string[] 相机5圆 = GLOBAL.cameras.GetBlobResult(Camera.Address[5], 15);
                                string[] 相机5Blob1 = GLOBAL.cameras.GetBlobResult(
                                                       Camera.AddressOffset(
                                                        Camera.Address[5],
                                                        (int)相机5blob1["起始地址"]),
                                                       (int)相机5blob1["长度"]);
                               // string[] 相机5Blob1 = GLOBAL.cameras.GetBlobResult(Camera.AddressOffset(Camera.Address[5], 15), 64);
                                string[] 相机5Blob2 = GLOBAL.cameras.GetBlobResult(Camera.AddressOffset(Camera.Address[5], 223), 64);
                                //string[] 相机5边缘 = GLOBAL.cameras.GetEdgeResult(Camera.AddressOffset(Camera.Address[5], 416), 11);

                                double radius = 0;
                                double[] 相机5偏移 = { 0, 0, 0 };
                                //double[] d_圆 = 相机5圆.Select(x => Convert.ToDouble(x)).ToArray();
                                double[] d_Blob1 = 相机5Blob1.Select(x => Convert.ToDouble(x)).ToArray();
                                double[] d_Blob2 = 相机5Blob2.Select(x => Convert.ToDouble(x)).ToArray();
                                
                                radius = 180 * Math.Atan(
                                    (d_Blob1[0] - d_Blob2[0])
                                   / (d_Blob1[1] - d_Blob2[1])
                                    )
                                    / Math.PI;
                                //180 * ATAN((x2 - x1) / (y2- y1)) / PI()


                                double offset_x = Blob基准点1[0] - d_Blob1[0];
                                double offset_y = Blob基准点1[1] - d_Blob1[1];
                                //double offset_x = ((Blob基准点1[0] - d_Blob1[0]) + (Blob基准点2[0] - d_Blob2[0])) / 2;
                                //double offset_y = ((Blob基准点1[1] - d_Blob1[1]) + (Blob基准点2[1] - d_Blob2[1])) / 2;
                                //double 圆offset_x = 圆基准点[0] - d_圆[0];
                                //double 圆offset_y = 圆基准点[1] - d_圆[1];

                                相机5偏移[0] = offset_x;
                                相机5偏移[1] = offset_y;
                                相机5偏移[2] = 相机5Blob角度 - radius;
                                

                                吸屏蔽片放料位置[0] -= OffsetToPulse(相机5偏移[0]);
                                吸屏蔽片放料位置[1] -= OffsetToPulse(相机5偏移[1]);
                                //可以屏蔽下面这句
                                //吸屏蔽片放料位置[2] += 角度转换上屏蔽片脉冲(相机5偏移[2]);


                                string camera_data =
                                    //DateTime.Now + "," + "上屏蔽片相机5圆" + "," + string.Join(",", 相机5圆) + "\n" +
                                    DateTime.Now + "," + "上屏蔽片相机5Blob1" + "," + string.Join(",", 相机5Blob1) + "\n" +
                                    DateTime.Now + "," + "上屏蔽片相机5Blob2" + "," + string.Join(",", 相机5Blob2) + "\n" +
                                    DateTime.Now + "," + "上屏蔽片相机5偏移" + "," + string.Join(",", 相机5偏移);
                                    //DateTime.Now + "," + "上屏蔽片相机5圆偏移" + "," + 圆offset_x + "," + 圆offset_y;
                                camera_log_file.WriteLine(camera_data);
                              
                                GLOBAL.plc.WriteDword(GLOBAL.config.Get("吸屏蔽片X轴放料位置_register"), 吸屏蔽片放料位置[0]);
                                GLOBAL.plc.WriteDword(GLOBAL.config.Get("吸屏蔽片Y轴放料位置_register"), 吸屏蔽片放料位置[1]);
                                GLOBAL.plc.WriteDword(GLOBAL.config.Get("吸屏蔽片Z轴放料位置_register"), 吸屏蔽片放料位置[2]);
                                GLOBAL.plc.WriteDword(GLOBAL.config.Get("吸屏蔽片W轴放料位置_register"), 吸屏蔽片放料位置[3], 角度转换上屏蔽片脉冲系数);
 


                                Log.Write("吸屏蔽片载具偏移:" + string.Join(",", 相机5偏移));
                            }
                            else
                            {
                                Log.Write("上屏蔽片上相机定位结果获取失败");
                                has_wrong = true;
                            }

                            if (has_wrong)
                            {
                                屏蔽片_NG++;
                                if (屏蔽片_NG==4)
                                {
                                    屏蔽片_NG = 0;
                                    GLOBAL.plc.WriteMBit(GLOBAL.config.Get("屏蔽片拍照失败报警_register"), "1");
                                }
                                Log.Write("上屏蔽片定位失败抛料");

                                GLOBAL.plc.WriteDword(GLOBAL.config.Get("吸屏蔽片X轴放料位置_register"), 吸屏蔽片抛料位置[0]);
                                GLOBAL.plc.WriteDword(GLOBAL.config.Get("吸屏蔽片Y轴放料位置_register"), 吸屏蔽片抛料位置[1]);
                                GLOBAL.plc.WriteDword(GLOBAL.config.Get("吸屏蔽片Z轴放料位置_register"), 吸屏蔽片抛料位置[2], 角度转换上屏蔽片脉冲系数);
                                //出错抛料,回环线不会运动
                                GLOBAL.plc.WriteMBit(GLOBAL.config.Get("吸屏蔽片失败抛料标志_register"), "1");
                            }
                            else
                            {
                                //改变当前吸屏蔽片工位屏蔽片状态
                                GLOBAL.station[5].Tray.有屏蔽片 = true;
                                屏蔽片_NG = 0;
                                GLOBAL.plc.WriteMBit(GLOBAL.config.Get("吸屏蔽片失败抛料标志_register"), "0");
                            }
                                


                            //切换到空任务
                            GLOBAL.cameras.SelectTask(5, (int)GLOBAL.config.configs["相机参数"]["空模板"]["相机5"]);
                            // 切换任务                       
                            GLOBAL.cameras.SelectTask(5, (int)GLOBAL.config.configs["相机参数"]["默认模板"]["相机5"]);

                            GLOBAL.plc.WriteMBit(GLOBAL.config.Get("吸屏蔽片上相机拍照完成_register"), "1");
                            //取消复位
                            Thread.Sleep(500);
                            //GLOBAL.plc.WriteMBit(GLOBAL.config.Get("吸屏蔽片上相机拍照完成_register"), "0");

                        }
                        else if (相机6触发 == "1")
                        {

                            int[] 吸屏蔽片抛料位置 = GLOBAL.config.configs["相机参数"]["吸屏蔽片抛料位置"].ToArray().Select(x => (int)(double)x).ToArray();
                            Thread.Sleep(interval);;
                            Result r1 = GLOBAL.cameras.GetTaskStatus(5);
                            Log.Write("出错相机5:" + r1.ToString());
                            if (r1 == Result.Passed)
                            {
                                var 相机5模板0参数 = GLOBAL.config.configs["相机参数"]["相机5"]["模板0"];
                                var 相机5blob1 = 相机5模板0参数["blob1"];
                                double[] Blob基准点1 = 相机5blob1["基准点"].ToArray().Select(x => (double)x).ToArray();
                                double[] Blob基准点2 = 相机5模板0参数["Blob2基准点"].ToArray().Select(x => (double)x).ToArray();
                                //double[] Blob基准点2 = 相机5模板0参数["Blob2基准点"].ToArray().Select(x => (double)x).ToArray();
                                //double[] 圆基准点 = 相机5模板0参数["圆基准点"].ToArray().Select(x => (double)x).ToArray();
                                //double 相机5Blob角度 = (double)相机5模板0参数["Blob角度"];
                                //第一次拍照
                                string[] 相机5圆 = GLOBAL.cameras.GetBlobResult(Camera.Address[5], 15);
                                string[] 相机5Blob1 = GLOBAL.cameras.GetBlobResult(
                                                           Camera.AddressOffset(
                                                            Camera.Address[5],
                                                            (int)相机5blob1["起始地址"]),
                                                           (int)相机5blob1["长度"]);
                                // string[] 相机5Blob1 = GLOBAL.cameras.GetBlobResult(Camera.AddressOffset(Camera.Address[5], 15), 64);
                                string[] 相机5Blob2 = GLOBAL.cameras.GetBlobResult(Camera.AddressOffset(Camera.Address[5], 223), 64);
                                //string[] 相机5边缘 = GLOBAL.cameras.GetEdgeResult(Camera.AddressOffset(Camera.Address[5], 416), 11);

                                double radius = 0;
                                double[] 相机5偏移 = { 0, 0, 0 };
                                double[] d_圆 = 相机5圆.Select(x => Convert.ToDouble(x)).ToArray();
                                double[] d_Blob1 = 相机5Blob1.Select(x => Convert.ToDouble(x)).ToArray();
                                double[] d_Blob2 = 相机5Blob2.Select(x => Convert.ToDouble(x)).ToArray();

                                radius = 180 * Math.Atan(
                                    (d_Blob1[1] - d_Blob2[1])
                                    / (d_Blob1[0] - d_Blob2[0]))
                                    / Math.PI;
                                //180 * ATAN((y2 - y1) / (x2- x1)) / PI()


                                //  double offset_x = Blob基准点1[0] - d_Blob1[0];
                                //  double offset_y = Blob基准点1[1] - d_Blob1[1];
                                double offset_x = ((Blob基准点1[0] - d_Blob1[0]) + (Blob基准点2[0] - d_Blob2[0])) / 2;
                                double offset_y = ((Blob基准点1[1] - d_Blob1[1]) + (Blob基准点2[1] - d_Blob2[1])) / 2;
                                //double 圆offset_x = 圆基准点[0] - d_圆[0];
                                //double 圆offset_y = 圆基准点[1] - d_圆[1];

                               // double 圆offset_x = 圆基准点[0] - d_圆[0];
                               // double 圆offset_y = 圆基准点[1] - d_圆[1];

                                相机5偏移[0] = offset_x;
                                相机5偏移[1] = offset_y;
                                //相机5偏移[2] = Blob角度 - radius;


                                //吸屏蔽片放料位置[0] -= OffsetToPulse(相机5偏移[0]);
                                //吸屏蔽片放料位置[1] -= OffsetToPulse(相机5偏移[1]);


                                string camera_data =
                                    DateTime.Now + "," + "出错上屏蔽片相机5圆" + "," + string.Join(",", 相机5圆) + "\n" +
                                    DateTime.Now + "," + "出错上屏蔽片相机5Blob" + "," + string.Join(",", 相机5Blob1) + "\n" +
                                    DateTime.Now + "," + "出错上屏蔽片相机5Blob1" + "," + string.Join(",", 相机5Blob2) + "\n" +
                                    DateTime.Now + "," + "出错上屏蔽片相机5偏移" + "," + string.Join(",", 相机5偏移);
                                    //DateTime.Now + "," + "出错上屏蔽片相机5圆偏移" + "," + 圆offset_x + "," + 圆offset_y;
                                camera_log_file.WriteLine(camera_data);

                            }

                            //出错抛料,回环线不会运动
                            GLOBAL.plc.WriteMBit(GLOBAL.config.Get("吸屏蔽片失败抛料标志_register"), "1");
                            GLOBAL.plc.WriteDword(GLOBAL.config.Get("吸屏蔽片X轴放料位置_register"), 吸屏蔽片抛料位置[0]);
                            GLOBAL.plc.WriteDword(GLOBAL.config.Get("吸屏蔽片Y轴放料位置_register"), 吸屏蔽片抛料位置[1]);
                            ////////////////////////////////////////////////////////////////
                            //切换到空任务
                            GLOBAL.cameras.SelectTask(5, (int)GLOBAL.config.configs["相机参数"]["空模板"]["相机5"]);
                            // 切换任务                       
                            GLOBAL.cameras.SelectTask(5, (int)GLOBAL.config.configs["相机参数"]["默认模板"]["相机5"]);
                            GLOBAL.plc.WriteMBit(GLOBAL.config.Get("吸屏蔽片上相机拍照完成_register"), "1");
                            Thread.Sleep(500);
                            //取消复位
                            //GLOBAL.plc.WriteMBit(GLOBAL.config.Get("吸屏蔽片上相机拍照完成_register"), "0");

                            //测试监视屏蔽片状态
                            //GLOBAL.station[5].Tray.有屏蔽片 = true;
                        }
                        else if (吸屏蔽片到达二次拍照位置 == "1")
                        {
                            int[] 吸屏蔽片放料位置 = GLOBAL.config.configs["相机参数"]["吸屏蔽片放料位置"].ToArray().Select(x => (int)(double)x).ToArray();
                            var 相机6模板0参数 = GLOBAL.config.configs["相机参数"]["相机6"]["模板0"];
                            var blob1 = 相机6模板0参数["blob1"];
                            var blob2 = 相机6模板0参数["blob2"];
                            double[] Blob1基准点 = blob1["基准点"].ToArray().Select(x => (double)x).ToArray();
                            double[] Blob2基准点 = blob2["基准点"].ToArray().Select(x => (double)x).ToArray();
                            //double 相机6Blob角度 = (double)相机6模板0参数["Blob角度"];
                            double 相机6Blob角度 = 180 * Math.Atan(
                                    (Blob2基准点[0] - Blob1基准点[0])
                                    / (Blob2基准点[1] - Blob1基准点[1]))
                                    / Math.PI;

                            Thread.Sleep(debug_delay);
                            Result r1 = GLOBAL.cameras.GetTaskStatus(6);
                            Log.Write("出错相机6第二次:" + r1.ToString());
                            if (r1 == Result.Passed)
                            {
                                string[] 相机6Blob1 = GLOBAL.cameras.GetBlobResult(
                                               Camera.AddressOffset(
                                                Camera.Address[6],
                                                (int)blob1["起始地址"]),
                                               (int)blob1["长度"]);
                                string[] 相机6Blob2 = GLOBAL.cameras.GetBlobResult(
                                               Camera.AddressOffset(
                                                Camera.Address[6],
                                                (int)blob2["起始地址"]),
                                               (int)blob2["长度"]);
                                //string[] 相机6边缘 = GLOBAL.cameras.GetEdgeResult(Camera.AddressOffset(Camera.Address[6], 416), 11);

                                double radius = 0;
                                double[] 相机6偏移 = { 0, 0, 0 };
                                double[] d_Blob定位器1 = 相机6Blob1.Select(x => Convert.ToDouble(x)).ToArray();
                                double[] d_Blob定位器2 = 相机6Blob2.Select(x => Convert.ToDouble(x)).ToArray();
                                //double[] d_边缘 = 相机6边缘.Select(x => Convert.ToDouble(x)).ToArray();

                                double blob_radius = 180 * Math.Atan(
                                    (d_Blob定位器2[0] - d_Blob定位器1[0])
                                    / (d_Blob定位器2[1] - d_Blob定位器1[1]))
                                    / Math.PI;
                                radius = blob_radius;
                                //radius = d_边缘[0];
                                //180 * ATAN((x2- x1) / (y2 - y1)) / PI()

                                //double offset_x = ((Blob1基准点[0] - d_Blob定位器1[0]) + (Blob2基准点[0] - d_Blob定位器2[0])) / 2;
                                // double offset_y = ((Blob1基准点[1] - d_Blob定位器1[1]) + (Blob2基准点[1] - d_Blob定位器2[1])) / 2;
                                double offset_x = Blob1基准点[0] - d_Blob定位器1[0];
                                double offset_y = Blob1基准点[1] - d_Blob定位器1[1];

                                相机6偏移[0] = offset_x;
                                相机6偏移[1] = offset_y;
                                //相机6偏移[2] = 边缘基准角度 - radius;
                                相机6偏移[2] = 相机6Blob角度 - radius;


                                string camera_data =
                                    DateTime.Now + "," + "出错上屏蔽片相机6第二次Blob1" + "," + string.Join(",", 相机6Blob1) + "\n" +
                                    DateTime.Now + "," + "出错上屏蔽片相机6第二次Blob2" + "," + string.Join(",", 相机6Blob2) + "\n" +
                                    DateTime.Now + "," + "出错上屏蔽片相机6第二次Blob角度" + "," + blob_radius + "\n" +
                                    //DateTime.Now + "," + "出错上屏蔽片相机6第二次边缘角度" + "," + radius + "\n" +
                                    DateTime.Now + "," + "出错上屏蔽片相机6第二次偏移" + "," + string.Join(",", 相机6偏移);
                                camera_log_file.WriteLine(camera_data);


                                //此处插入料盘偏移计算,然后算出最终对基准位置偏移

                                //吸屏蔽片放料位置[0] += OffsetToPulse(相机6偏移[0]);
                                //吸屏蔽片放料位置[1] += OffsetToPulse(相机6偏移[1]);
                                //吸屏蔽片放料位置[2] += 角度转换上屏蔽片脉冲(相机6偏移[2]);

                                Log.Write("出错吸屏蔽片第二次拍照偏移:" + string.Join(",", 相机6偏移));
                            }


                            GLOBAL.plc.WriteDword(GLOBAL.config.Get("吸屏蔽片X轴放料位置_register"), 吸屏蔽片放料位置[0]);
                            GLOBAL.plc.WriteDword(GLOBAL.config.Get("吸屏蔽片Y轴放料位置_register"), 吸屏蔽片放料位置[1]);
                            GLOBAL.plc.WriteDword(GLOBAL.config.Get("吸屏蔽片W轴放料位置_register"), 吸屏蔽片放料位置[3], 角度转换上屏蔽片脉冲系数);


                            GLOBAL.plc.WriteMBit(GLOBAL.config.Get("吸屏蔽片下相机第二次拍照完成_register"), "1");
                            Thread.Sleep(interval);
                            //取消复位
                            //GLOBAL.plc.WriteMBit(GLOBAL.config.Get("吸屏蔽片下相机第二次拍照完成_register"), "0");
                        }
                    }

                }
                catch (Exception e)
                {
                    Log.Write(e.ToString());
                }
                Thread.Sleep(interval);
            }
        }
        /// <summary>
        /// 实际使用相机2
        /// </summary>
        private void 螺母检测触发方法()
        {
            while (loop)
            {
                try
                {
                    if (GLOBAL.plc.IsConnect && GLOBAL.cameras.IsConnect && GLOBAL.运行标志 == "1" && GLOBAL.总警告 == "0")
                    {
                        string 相机3触发 = "0";//螺母检测相机

                        GLOBAL.plc.ReadMBit(GLOBAL.config.Get("相机3触发_register"), ref 相机3触发);
                        if (相机3触发 == "1")
                        {
                            //bool has_wrong = false;
                            string 检测结果 = "0";
                            //Thread.Sleep(debug_delay);
                            Result r1 = Result.None;
                            for (int i = 0; i < max_wait; i++)
                            {
                                r1 = GLOBAL.cameras.GetTaskStatus(2);
                                if (r1 != Result.None)
                                    break;
                                Thread.Sleep(interval);

                            }
                            //Result r1 = GLOBAL.cameras.GetTaskStatus(2);
                            Log.Write("相机2:" + r1.ToString());
                            if (r1 == Result.Passed)
                            {
                                string[] coutour_result1 = GLOBAL.cameras.GetContourMatchResult(Camera.AddressOffset(Camera.Address[2], 438), 64);
                                string[] coutour_result2 = GLOBAL.cameras.GetContourMatchResult(Camera.AddressOffset(Camera.Address[2], 550), 64);

                                string camera_data =
                                             DateTime.Now + "," + "轮廓1匹配率" + "," + Convert.ToDouble(coutour_result1[0]) + "\n" +
                                             DateTime.Now + "," + "轮廓1旋转角度" + "," + Convert.ToDouble(coutour_result1[1]) + "\n"+
                                             DateTime.Now + "," + "轮廓2匹配率" + "," + Convert.ToDouble(coutour_result2[0]) + "\n" +
                                             DateTime.Now + "," + "轮廓2旋转角度" + "," + Convert.ToDouble(coutour_result2[1]) +
                                             string.Join(",", DateTime.Now , "相机2检测状态:", r1.ToString());

                                camera_log_file.WriteLine(camera_data);
                                检测结果 = "1";

                            }
                            else
                            {
                                Log.Write("螺母检测结果获取失败");
                               // has_wrong = true;
                            }

                            //切换到空任务
                            GLOBAL.cameras.SelectTask(2, (int)GLOBAL.config.configs["相机参数"]["空模板"]["相机2"]);
                            //切换任务
                            GLOBAL.cameras.SelectTask(2, (int)GLOBAL.config.configs["相机参数"]["默认模板"]["相机2"]);
                            //if (has_wrong)
                            //    Log.Write("螺母检测失败");
                            GLOBAL.plc.WriteMBit(GLOBAL.config.Get("螺母检测拍照完成_register"), "1");
                            Thread.Sleep(interval);
                            //默认不通过
                            GLOBAL.plc.WriteMBit(GLOBAL.config.Get("螺母检测结果_register"), 检测结果);

                            GLOBAL.plc.WriteMBit(GLOBAL.config.Get("螺母检测拍照完成_register"), "0");

                        }
                    }

                }
                catch (Exception e)
                {
                    Log.Write(e.ToString());
                }
                Thread.Sleep(interval);
            }
        }
        private void 螺母测试方法()
        {
            while (loop)
            {
                try
                {
                    if (GLOBAL.plc.IsConnect && GLOBAL.cameras.IsConnect && GLOBAL.运行标志 == "1" && GLOBAL.总警告 == "0")
                    {
                        string 相机2触发 = "0";//螺母检测相机

                        GLOBAL.plc.ReadMBit(GLOBAL.config.Get("相机2触发_register"), ref 相机2触发);
                        if (相机2触发 == "1")
                        {
                            var 相机1模板2参数 = GLOBAL.config.configs["相机参数"]["相机1"]["模板2"];
                            var 圆1 = 相机1模板2参数["圆1"];
                            var 圆2 = 相机1模板2参数["圆2"];
                            //bool has_wrong = false;
                            //Thread.Sleep(debug_delay);
                            Result r1 = Result.None;
                            for (int i = 0; i < max_wait; i++)
                            {
                                r1 = GLOBAL.cameras.GetTaskStatus(1);
                                if (r1 != Result.None)
                                    break;
                                Thread.Sleep(interval);

                            }
                            //Result r1 = GLOBAL.cameras.GetTaskStatus(2);
                            Log.Write("相机1:" + r1.ToString());
                            if (r1 == Result.Passed)
                            {
                                string[] 相机1左圆 = GLOBAL.cameras.GetCircleResult(
                                       Camera.AddressOffset(
                                        Camera.Address[1],
                                        (int)圆1["起始地址"]),
                                       (int)圆1["长度"]);
                                string[] 相机1右圆 = GLOBAL.cameras.GetCircleResult(
                                        Camera.AddressOffset(
                                        Camera.Address[1],
                                        (int)圆2["起始地址"]),
                                        (int)圆2["长度"]);
                                string camera_data =
                                                 DateTime.Now + "," + "测试相机1右圆" + "," + string.Join(",", 相机1右圆) + "\n" +
                                                 DateTime.Now + "," + "测试相机1左圆" + "," + string.Join(",", 相机1左圆) + "\n" +
                                                 string.Join(",", DateTime.Now, "相机2检测状态:", r1.ToString());
                                camera_log_file.WriteLine(camera_data);


                                Log.Write("测试相机1左圆:" + string.Join(",", 相机1左圆));
                                Log.Write("测试相机1右圆:" + string.Join(",", 相机1右圆));
                            }
                            else
                            {
                                Log.Write("螺母检测结果获取失败");
                                // has_wrong = true;
                            }

                            //切换到空任务
                            GLOBAL.cameras.SelectTask(1, (int)GLOBAL.config.configs["相机参数"]["空模板"]["相机1"]);
                            //切换任务
                            GLOBAL.cameras.SelectTask(1, (int)GLOBAL.config.configs["相机参数"]["默认模板"]["相机1"]);
                            //if (has_wrong)
                            //    Log.Write("螺母检测失败");
                            GLOBAL.plc.WriteMBit(GLOBAL.config.Get("吸螺母下相机拍照完成_register"), "1");
                            Thread.Sleep(300);
                        }
                    }

                }
                catch (Exception e)
                {
                    Log.Write(e.ToString());
                }
                Thread.Sleep(interval);
            }
        }
        /// <summary>
        /// 实际使用相机3,4
        /// </summary>
        private void 上cg触发方法()
        {
            error_flags["上cg错误"] = 0;
            Stopwatch sw = new Stopwatch();
            sw.Start();
            while (loop)
            {
                try
                {
                    //机器手
                    if (GLOBAL.robot["机器手1"].IsConnect && GLOBAL.cameras.IsConnect && GLOBAL.运行标志 == "1")
                    {
                        GLOBAL.cameras.SelectTask(4, (int)GLOBAL.config.configs["相机参数"]["默认模板"]["相机4"]);
                        string 上料ROBOT告诉PLC料盘已上料完成 = "";
                        GLOBAL.plc.ReadMBit(GLOBAL.config.Get("上料ROBOT告诉PLC料盘已上料完成_register"), ref 上料ROBOT告诉PLC料盘已上料完成);
                        //Thread.Sleep(200);
                        if (GLOBAL.robot["机器手1"].上料机器手第0次拍照触发())
                        {
                            //流异常检测,当重复触发次数低于1秒时认为出错,累计错误满足条件断开重连
                            //GLOBAL.robot["机器手1"].上料机器手第0次拍照完成();
                            sw.Stop();
                            if (sw.ElapsedMilliseconds < 1000)
                                error_flags["上cg错误"] += 1;
                            sw.Restart();
                            // Result r1 = GLOBAL.cameras.GetTaskStatus(3);
                            Thread.Sleep(debug_delay);
                            Result r0 = GLOBAL.cameras.GetTaskStatus(4);
                            Log.Write("相机4第0次拍照状态:" + r0);

                            if (r0 != Result.Passed || !GLOBAL.robot["机器手1"].IsConnect)
                            {
                                cg_NG++;
                                Log.Write("CG放反了");
                                //  GLOBAL.robot["机器手1"].上料机器手第0次拍照完成();
                                GLOBAL.robot["机器手1"].CG方向("1");
                            }
                            else
                            {

                                GLOBAL.cameras.SelectTask(4, (int)GLOBAL.config.configs["相机参数"]["检测模板"]["相机4"]);
                                Thread.Sleep(500);
                                // GLOBAL.robot["机器手1"].上料机器手第0次拍照完成();

                                GLOBAL.robot["机器手1"].CG方向("0");

                                while (!GLOBAL.robot["机器手1"].上料机器手第一次拍照触发() && GLOBAL.robot["机器手1"].IsConnect && GLOBAL.cameras.IsConnect && GLOBAL.运行标志 == "1")
                                {
                                    Thread.Sleep(interval);
                                }
                                bool has_wrong = false;
                                double[] 机器手偏移 = { 0, 0, 0 };
                                var 相机4模板0参数 = GLOBAL.config.configs["相机参数"]["相机4"]["模板0"];
                                var 相机3模板0参数 = GLOBAL.config.configs["相机参数"]["相机3"]["模板0"];

                                double[] 相机3Blob基准点 = 相机3模板0参数["bolb器准点"].ToArray().Select(x => (double)x).ToArray();
                                double[] 相机3Blob坐标偏移 = 相机3模板0参数["坐标偏移"].ToArray().Select(x => (double)x).ToArray();
                                double[] 相机4SubBlob1基准点 = 相机4模板0参数["SubBlob1基准点"].ToArray().Select(x => (double)x).ToArray();
                                //double[] 相机4SubBlob2基准点 = 相机4模板0参数["SubBlob2基准点"].ToArray().Select(x => (double)x).ToArray();
                                //double Blob基准角度 = (double)相机3模板0参数["基准角度"];
                                double Blob基准角度 = 180 * Math.Atan(
                                        ((相机3Blob基准点[1] + 相机3Blob坐标偏移[1]) - 相机4SubBlob1基准点[1])
                                        / ((相机3Blob基准点[0] + 相机3Blob坐标偏移[0]) - 相机4SubBlob1基准点[0]))
                                        / Math.PI;
                                //double 边缘基准角度 = (double)相机4模板0参数["边缘基准角度"];
                                //double 基准角度 = (double)相机4模板0参数["基准角度"];
                                //double[] 轮廓匹配基准点 = 相机4模板0参数["轮廓匹配基准点"].ToArray().Select(x => (double)x).ToArray();
                                //double[] bolb器准点 = 相机4模板0参数["bolb器准点"].ToArray().Select(x => (double)x).ToArray();
                                Result r1 = GLOBAL.cameras.GetTaskStatus(3);
                                Result r2 = GLOBAL.cameras.GetTaskStatus(4);
                                /*
                                //等待一次拍照信号
                                for (int i = 0;i < max_wait;i++)
                                {
                                    Console.WriteLine("相机3" + r1.ToString());
                                    Console.WriteLine("相机4" + r2.ToString());
                                    if (r1 != Result.None && r2 != Result.None)
                                        break;
                                    r1 = GLOBAL.cameras.GetTaskStatus(3);
                                    r2 = GLOBAL.cameras.GetTaskStatus(4);
                                    Thread.Sleep(interval);
                                }
                                */
                                //临时演示
                                Thread.Sleep(debug_delay);
                                r1 = GLOBAL.cameras.GetTaskStatus(3);
                                r2 = GLOBAL.cameras.GetTaskStatus(4);

                                Log.Write("相机3:" + r1.ToString());
                                Log.Write("相机4:" + r2.ToString());
                                if (r1 == Result.Passed && r2 == Result.Passed)
                                {
                                    //第一次拍照
                                    string[] 相机3Blob = GLOBAL.cameras.GetBlobResult(Camera.Address[3], 64);
                                    //string[] 相机4边缘 = GLOBAL.cameras.GetEdgeResult(Camera.AddressOffset(Camera.Address[4], 208), 11);
                                    string[] 相机4SubBlob = GLOBAL.cameras.GetSubBlobResult(Camera.Address[4], 64);
                                    //string[] 相机4轮廓匹配 = GLOBAL.cameras.GetContourResult(Camera.AddressOffset(Camera.Address[4], 208), 111);

                                    //sw.Start();
                                    double[] 相机3Blob1 = 相机3Blob.Select(x => Convert.ToDouble(x)).ToArray(); ;
                                    double[] 相机4SubBlob1 = { Convert.ToDouble(相机4SubBlob[0]), Convert.ToDouble(相机4SubBlob[1]) };
                                    double[] 相机4SubBlob2 = { Convert.ToDouble(相机4SubBlob[2]), Convert.ToDouble(相机4SubBlob[3]) };
                                    double radius = 0;
                                    //double[] d_相机4轮廓匹配 = 相机4轮廓匹配.Select(x => Convert.ToDouble(x)).ToArray();
                                    //double[] d_相机4Blob = 相机4SubBlob.Select(x => Convert.ToDouble(x)).ToArray();

                                    double offset_x = ((相机4SubBlob1基准点[0] - 相机4SubBlob1[0]) + (相机3Blob基准点[0] - 相机3Blob1[0])) / 2;
                                    double offset_y = ((相机4SubBlob1基准点[1] - 相机4SubBlob1[1]) + (相机3Blob基准点[1] - 相机3Blob1[1])) / 2;

                                    //将相机3点位坐标补偿至相机4坐标系
                                    相机3Blob1[0] += 相机3Blob坐标偏移[0];
                                    相机3Blob1[1] += 相机3Blob坐标偏移[1];

                                    radius = 180 * Math.Atan(
                                        (相机3Blob1[1] - 相机4SubBlob1[1])
                                        / (相机3Blob1[0] - 相机4SubBlob1[0]))
                                        / Math.PI;
                                    radius = Blob基准角度 - radius;
                                    //radius = 边缘基准角度 - Convert.ToDouble(相机4边缘[0]);
                                    //180 * ATAN((Y2- Y1) / (X2 - X1)) / PI()

                                    //double offset_x = ((SubBlob1基准点[0] - 相机4SubBlob1[0]) + (SubBlob2基准点[0] - 相机4SubBlob2[0])) / 2;
                                    //double offset_y = ((SubBlob1基准点[1] - 相机4SubBlob1[1]) + (SubBlob2基准点[1] - 相机4SubBlob2[1])) / 2;

                                    //相机4偏移[0] = center_x;
                                    //相机4偏移[1] = center_y;
                                    机器手偏移[2] = radius;

                                    string camera_data =
                                        DateTime.Now + "," + "上cg第一次相机3Blob" + "," + string.Join(",", 相机3Blob1) + "\n" +
                                        DateTime.Now + "," + "上cg第一次相机4Subblob1" + "," + string.Join(",", 相机4SubBlob1) + "\n" +
                                        //DateTime.Now + "," + "上cg第一次相机4Subblob2" + "," + string.Join(",", 相机4SubBlob2) + "\n" +
                                        DateTime.Now + "," + "上cg第一次相机4角度" + "," + 机器手偏移[2] + "\n" +
                                        DateTime.Now + "," + "上cg第一次相机4偏移" + "," + string.Join(",", offset_x, offset_y, radius);
                                    camera_log_file.WriteLine(camera_data);

                                    Log.Write("机器人第一次放料偏移:" + string.Join(",", 机器手偏移));
                                    //sw.Stop();
                                    //Log.Write("机器人第一次放料计算时间:" + sw.Elapsed);
                                }
                                else
                                {
                                    Log.Write("上cg片相机4一次定位结果获取失败");
                                    has_wrong = true;
                                }
                                /*
                                //切换到空任务
                                GLOBAL.cameras.SelectTask(3, (int)GLOBAL.config.configs["相机参数"]["空模板"]["相机3"]);
                                //切换任务
                                GLOBAL.cameras.SelectTask(3, (int)GLOBAL.config.configs["相机参数"]["默认模板"]["相机3"]);
                                //切换到空任务
                                GLOBAL.cameras.SelectTask(4, (int)GLOBAL.config.configs["相机参数"]["空模板"]["相机4"]);
                                //切换任务
                                GLOBAL.cameras.SelectTask(4, (int)GLOBAL.config.configs["相机参数"]["默认模板"]["相机4"]);
                                */

                                //给机器人角度偏移
                                GLOBAL.robot["机器手1"].上料机器手第一次拍照偏移(机器手偏移[0], 机器手偏移[1], 机器手偏移[2]);

                                //string msg = string.Join(";", 爱普生_Robot.上料机器手["机器手旋转偏移角度"], 机器手偏移[2]);//发送角度
                                //GLOBAL.robot["机器手1"].Send(msg);
                                //给机器人拍照完成信号                               
                                //GLOBAL.robot["机器手1"].Send(爱普生_Robot.上料机器手["第一次拍照完成"]);//表示第一次拍照完成

                                //Thread.Sleep(interval);

                                //等待第二次拍照信号
                                while (!GLOBAL.robot["机器手1"].上料机器手第二次拍照触发() && GLOBAL.robot["机器手1"].IsConnect && GLOBAL.cameras.IsConnect && GLOBAL.运行标志 == "1")
                                {
                                    GLOBAL.robot["机器手1"].上料机器手第一次拍照完成();
                                    Thread.Sleep(interval);
                                }

                                r1 = Result.None;
                                r2 = Result.None;
                                /*
                                //等待第二次结果信号
                                for (int i = 0; i < max_wait; i++)
                                {
                                    Console.WriteLine("相机3" + r1.ToString());
                                    Console.WriteLine("相机4" + r2.ToString());
                                    if (r1 != Result.None && r2 != Result.None)
                                        break;
                                    r1 = GLOBAL.cameras.GetTaskStatus(3);
                                    r2 = GLOBAL.cameras.GetTaskStatus(4);
                                    Thread.Sleep(interval);
                                }
                                */

                                //Thread.Sleep(interval);
                                Thread.Sleep(debug_delay);
                                r1 = GLOBAL.cameras.GetTaskStatus(3);
                                r2 = GLOBAL.cameras.GetTaskStatus(4);
                                Log.Write("相机3:" + r1.ToString());
                                Log.Write("相机4:" + r2.ToString());
                                //第二次拍照
                                if (r1 == Result.Passed && r2 == Result.Passed)
                                {
                                    string[] 相机3Blob = GLOBAL.cameras.GetBlobResult(Camera.Address[3], 64);
                                    //string[] 相机4边缘 = GLOBAL.cameras.GetEdgeResult(Camera.AddressOffset(Camera.Address[4], 208), 11);
                                    string[] 相机4SubBlob = GLOBAL.cameras.GetSubBlobResult(Camera.Address[4], 64);
                                    //string[] 相机4轮廓匹配 = GLOBAL.cameras.GetContourResult(Camera.AddressOffset(Camera.Address[4], 208), 111);

                                    //sw.Start();
                                    double[] 相机3Blob1 = 相机3Blob.Select(x => Convert.ToDouble(x)).ToArray(); ;
                                    double[] 相机4SubBlob1 = { Convert.ToDouble(相机4SubBlob[0]), Convert.ToDouble(相机4SubBlob[1]) };
                                    double[] 相机4SubBlob2 = { Convert.ToDouble(相机4SubBlob[2]), Convert.ToDouble(相机4SubBlob[3]) };
                                    double radius = 0;
                                    //double[] d_相机4轮廓匹配 = 相机4轮廓匹配.Select(x => Convert.ToDouble(x)).ToArray();
                                    //double[] d_相机4Blob = 相机4SubBlob.Select(x => Convert.ToDouble(x)).ToArray();
                                    //将相机3点位坐标补偿至相机4坐标系

                                    double offset_x = ((相机4SubBlob1基准点[0] - 相机4SubBlob1[0]) + (相机3Blob基准点[0] - 相机3Blob1[0])) / 2;
                                    double offset_y = ((相机4SubBlob1基准点[1] - 相机4SubBlob1[1]) + (相机3Blob基准点[1] - 相机3Blob1[1])) / 2;

                                    相机3Blob1[0] += 相机3Blob坐标偏移[0];
                                    相机3Blob1[1] += 相机3Blob坐标偏移[1];

                                    radius = 180 * Math.Atan(
                                        (相机3Blob1[1] - 相机4SubBlob1[1])
                                        / (相机3Blob1[0] - 相机4SubBlob1[0]))
                                        / Math.PI;
                                    radius = Blob基准角度 - radius;
                                    //radius = 边缘基准角度 - Convert.ToDouble(相机4边缘[0]);
                                    //180 * ATAN((x2- x1) / (y2 - y1)) / PI()

                                    //double offset_x = ((SubBlob1基准点[0] - 相机4SubBlob1[0]) + (SubBlob2基准点[0] - 相机4SubBlob2[0])) / 2;
                                    //double offset_y = ((SubBlob1基准点[1] - 相机4SubBlob1[1]) + (SubBlob2基准点[1] - 相机4SubBlob2[1])) / 2;

                                    机器手偏移[0] = offset_x;
                                    机器手偏移[1] = offset_y;
                                    //相机4偏移[2] = radius;

                                    string camera_data =
                                        DateTime.Now + "," + "上cg第二次相机3Blob" + "," + string.Join(",", 相机3Blob1) + "\n" +
                                        DateTime.Now + "," + "上cg第二次相机4Subblob1" + "," + string.Join(",", 相机4SubBlob1) + "\n" +
                                        //DateTime.Now + "," + "上cg第二次相机4Subblob2" + "," + string.Join(",", 相机4SubBlob2) + "\n" +
                                        DateTime.Now + "," + "上cg第二次相机4角度" + "," + radius + "\n" +
                                        DateTime.Now + "," + "上cg第二次相机4偏移" + "," + string.Join(",", offset_x, offset_y, radius);
                                    camera_log_file.WriteLine(camera_data);
                                    Log.Write("机器人放料第二次偏移:" + string.Join(",", 机器手偏移[0], 机器手偏移[1], radius));
                                    //sw.Stop();
                                    //Log.Write("机器人第二次放料计算时间:" + sw.Elapsed);
                                }
                                else
                                {
                                    Log.Write("上cg片相机4二次定位结果获取失败");
                                    has_wrong = true;
                                }

                                if (has_wrong)
                                {
                                    cg_NG++;
                                    Log.Write("上cg片定位失败");
                                    GLOBAL.robot["机器手1"].拍照失败抛料();
                                }

                                /*
                                //切换到空任务
                                GLOBAL.cameras.SelectTask(3, (int)GLOBAL.config.configs["相机参数"]["空模板"]["相机3"]);
                                //切换任务
                                GLOBAL.cameras.SelectTask(3, (int)GLOBAL.config.configs["相机参数"]["默认模板"]["相机3"]);
                                //切换到空任务
                                GLOBAL.cameras.SelectTask(4, (int)GLOBAL.config.configs["相机参数"]["空模板"]["相机4"]);
                                //切换任务
                                GLOBAL.cameras.SelectTask(4, (int)GLOBAL.config.configs["相机参数"]["默认模板"]["相机4"]);
                                */

                                //给机器人角度偏移
                                GLOBAL.robot["机器手1"].上料机器手第二次拍照偏移(机器手偏移[0], 机器手偏移[1], 机器手偏移[2]);
                                //msg = string.Join(";", 爱普生_Robot.上料机器手["机器手偏移坐标"], 机器手偏移[0], 机器手偏移[1]);//发送x,y偏移
                                //GLOBAL.robot["机器手1"].Send(msg);
                                //第二次拍照完成
                                GLOBAL.robot["机器手1"].上料机器手第二次拍照完成();
                                //GLOBAL.robot["机器手1"].Send(爱普生_Robot.上料机器手["第二次拍照完成"]);
                                //最好不要触发
                                /*
                                else if (GLOBAL.robot["机器手1"].上料机器手第二次拍照触发())
                                {
                                    Log.Write("出错上料机器手第二次拍照触发");

                                    GLOBAL.robot["机器手1"].上料机器手第二次拍照完成();
                                    //GLOBAL.robot["机器手1"].Send(爱普生_Robot.上料机器手["第二次拍照完成"]);//表示第二次拍照完成

                                }
                                */

                                error_flags["上cg错误"] = 0;
                            }


                        }
                        //最好不要触发
                        else if (GLOBAL.robot["机器手1"].上料机器手第一次拍照触发())
                        {
                            Log.Write("出错上料机器手第一次拍照触发");

                            GLOBAL.robot["机器手1"].上料机器手第一次拍照完成();
                            //给机器人角度偏移
                            GLOBAL.robot["机器手1"].上料机器手第一次拍照偏移(0, 0, 0);
                            error_flags["上cg错误"] += 1;
                            //GLOBAL.robot["机器手1"].Send(爱普生_Robot.上料机器手["第二次拍照完成"]);//表示第二次拍照完成

                        }
                        //最好不要触发
                        else if (GLOBAL.robot["机器手1"].上料机器手第二次拍照触发())
                        {
                            Log.Write("出错上料机器手第二次拍照触发");

                            GLOBAL.robot["机器手1"].上料机器手第二次拍照完成();
                            GLOBAL.robot["机器手1"].上料机器手无偏移坐标();

                            error_flags["上cg错误"] += 1;
                            //GLOBAL.robot["机器手1"].Send(爱普生_Robot.上料机器手["第二次拍照完成"]);//表示第二次拍照完成

                        }

                        //if (GLOBAL.robot["机器手1"].)
                        //{
                        //    GLOBAL.plc.WriteMBit(GLOBAL.config.Get("上CG工位载具到位信号复位_register"), "0");
                        //}

                        if (error_flags["上cg错误"] >= max_error)
                        {
                            GLOBAL.robot["机器手1"].DisConnect();
                            error_flags["上cg错误"] = 0;
                        }

                        //if (GLOBAL.robot["机器手1"].上料机器人系统报错())
                        //{
                        //    GLOBAL.plc.WriteMBit(GLOBAL.config.Get("机器人系统错误报警_register"), "1");
                        //}
                    }

                }
                catch (Exception e)
                {
                    Log.Write(e.ToString());
                }

                Thread.Sleep(interval);
            }
        }

        private void 上cg扫码触发方法()
        {
            error_flags["上cg错误"] = 0;
            Stopwatch sw = new Stopwatch();
            sw.Start();
            while (loop)
            {
                try
                {
                    //机器手
                    if (GLOBAL.robot["机器手1"].IsConnect &&GLOBAL.扫码枪["扫码枪1"].IsConnect&& GLOBAL.cameras.IsConnect && GLOBAL.运行标志 == "1")
                    //if (GLOBAL.robot["机器手1"].IsConnect && GLOBAL.cameras.IsConnect && GLOBAL.运行标志 == "1")
                    {
                        //GLOBAL.cameras.SelectTask(4, (int)GLOBAL.config.configs["相机参数"]["默认模板"]["相机4"]);
                        //Thread.Sleep(200);
                        if (GLOBAL.robot["机器手1"].扫码触发())
                        {
                            //流异常检测,当重复触发次数低于1秒时认为出错,累计错误满足条件断开重连
                            sw.Stop();
                            if (sw.ElapsedMilliseconds < 1000)
                                error_flags["上cg错误"] += 1;

                            // Result r1 = GLOBAL.cameras.GetTaskStatus(3);
                            //Thread.Sleep(debug_delay);
                            Thread.Sleep(interval);
                            // Result r0 = GLOBAL.cameras.GetTaskStatus(4);
                            //Log.Write("相机4第0次拍照状态:" + r0);
                            string[] result = new string[] { };

                            bool 扫码结果 = false;
                            for (int i = 0; i < max_fail; i++)
                            {
                                if (!扫码结果&& GLOBAL.扫码枪["扫码枪1"].IsConnect)
                                    扫码结果 = GLOBAL.扫码枪["扫码枪1"].GetBarCode(ref result);//扫码结果标志,均失败则ng
                                else
                                    i = max_fail;
                                Thread.Sleep(interval);
                            }
                            GLOBAL.统计数据.上CG_Barcode = string.Join(",", result);
                            Log.Write("上料CG条码:" + string.Join(",", result));
                            Console.WriteLine("上料CG条码:" + string.Join(",", result));

                            sw.Restart();
                            //bool 扫码结果 = GLOBAL.扫码枪["扫码枪1"].GetBarCode(ref result);

                            if (GLOBAL.config.Get("扫码_enable") == "否")
                            {
                                Log.Write("扫码未启用");
                                扫码结果 = true;
                            }
                            if (!扫码结果)
                            {
                                GLOBAL.统计数据.上CG_Count_NG++;
                                GLOBAL.robot["机器手1"].扫码完成();
                                GLOBAL.robot["机器手1"].CG方向("1");
                                Log.Write("上料扫码失败");
                                Thread.Sleep(interval);
                                continue;
                            }
                            else
                            {
                                GLOBAL.统计数据.上CG_Count_OK++;
                            }
                            

                            bool SFC结果 = false;

                            if (GLOBAL.config.Get("SFC_enable") == "是"&& 扫码结果)
                            {
                                var 上料确认json = 获取上料确认数据();
                                var 过站签收json = 初始化过站签收();
                                bool 上料确认结果 = true;
                                bool 过站确认_签收 = true;
                                foreach (var barcode in result)
                                {
                                    上料确认json["prod_code"] = barcode;
                                    过站签收json["prod_barcode"] = barcode;
                                    var t1 = GLOBAL.sfc.上料确认(上料确认json);
                                    t1.Wait();
                                    //Console.WriteLine(上料确认json.ToString());
                                    if (t1.Result)
                                    {

                                        var t2 = GLOBAL.sfc.过站签收(过站签收json, 3, process_name.Frame签收);
                                        t2.Wait();
                                        //Console.WriteLine(过站签收json.ToString());
                                        if (!t2.Result)
                                        {
                                            Log.Write(barcode + "过站签收失败");
                                            过站确认_签收 = false;
                                        }
                                    }
                                    else
                                    {
                                        Log.Write(barcode + "上料确认失败");
                                        上料确认结果 = false;
                                    }
                                    break;
                                }

                                if (上料确认结果 && 过站确认_签收)
                                    SFC结果 = true;
                            }
                            else
                            {
                                SFC结果 = true;
                                Log.Write("SFC未启用");

                            }


                            //GLOBAL.station[1].Tray.Product.Barcode = result;
                            //GLOBAL.robot["机器手2"].Send(爱普生_Robot.下料机器手["扫码枪取结果完成标志1"]);

                            if (!SFC结果)
                            {
                                cg_NG++;
                                Log.Write("上料确认失败");
                                GLOBAL.robot["机器手1"].扫码完成();
                                GLOBAL.robot["机器手1"].CG方向("1");
                                Thread.Sleep(interval);
                                continue;
                            }
                            else
                            {
                                if (GLOBAL.config.Get("SFC_enable") == "是")
                                    Log.Write("上料确认和签收成功");
                                //GLOBAL.cameras.SelectTask(4, (int)GLOBAL.config.configs["相机参数"]["检测模板"]["相机4"]);
                                //Thread.Sleep(500);

                                GLOBAL.robot["机器手1"].扫码完成();
                                GLOBAL.robot["机器手1"].CG方向("0");

                                while (!GLOBAL.robot["机器手1"].上料机器手第一次拍照触发() && GLOBAL.robot["机器手1"].IsConnect && GLOBAL.cameras.IsConnect && GLOBAL.运行标志 == "1")
                                {
                                    Thread.Sleep(interval);
                                }
                                bool has_wrong = false;
                                double[] 机器手偏移 = { 0, 0, 0 };
                                var 相机4模板0参数 = GLOBAL.config.configs["相机参数"]["相机4"]["模板0"];
                                var 相机3模板0参数 = GLOBAL.config.configs["相机参数"]["相机3"]["模板0"];
                                var 相机3blob = 相机3模板0参数["blob"];
                                var 相机4SubBlob参数 = 相机4模板0参数["SubBlob"];
                                double[] 相机3Blob基准点 = 相机3blob["基准点"].ToArray().Select(x => (double)x).ToArray();
                                double[] 相机3Blob坐标偏移 = 相机3模板0参数["坐标偏移"].ToArray().Select(x => (double)x).ToArray();
                                double[] 相机4SubBlob1基准点 = 相机4SubBlob参数["基准点"].ToArray().Select(x => (double)x).ToArray();
                                //double[] 相机4SubBlob2基准点 = 相机4模板0参数["SubBlob2基准点"].ToArray().Select(x => (double)x).ToArray();
                                //double Blob基准角度 = (double)相机3模板0参数["基准角度"];
                                double Blob基准角度 = 180 * Math.Atan(
                                        ((相机3Blob基准点[1] + 相机3Blob坐标偏移[1]) - 相机4SubBlob1基准点[1])
                                        / ((相机3Blob基准点[0] + 相机3Blob坐标偏移[0]) - 相机4SubBlob1基准点[0]))
                                        / Math.PI;
                                //double 边缘基准角度 = (double)相机4模板0参数["边缘基准角度"];
                                //double 基准角度 = (double)相机4模板0参数["基准角度"];
                                //double[] 轮廓匹配基准点 = 相机4模板0参数["轮廓匹配基准点"].ToArray().Select(x => (double)x).ToArray();
                                //double[] bolb器准点 = 相机4模板0参数["bolb器准点"].ToArray().Select(x => (double)x).ToArray();
                                Result r1 = GLOBAL.cameras.GetTaskStatus(3);
                                Result r2 = GLOBAL.cameras.GetTaskStatus(4);
                                
                                //等待一次拍照信号
                                for (int i = 0;i < max_wait;i++)
                                {
                                    //Console.WriteLine("相机3" + r1.ToString());
                                    //Console.WriteLine("相机4" + r2.ToString());
                                    if (r1 != Result.None && r2 != Result.None)
                                        break;
                                    r1 = GLOBAL.cameras.GetTaskStatus(3);
                                    r2 = GLOBAL.cameras.GetTaskStatus(4);
                                    Thread.Sleep(interval);
                                }
                                /*
                                //临时演示
                                Thread.Sleep(debug_delay);
                                r1 = GLOBAL.cameras.GetTaskStatus(3);
                                r2 = GLOBAL.cameras.GetTaskStatus(4);
                                */

                                Log.Write("相机3:" + r1.ToString());
                                Log.Write("相机4:" + r2.ToString());
                                if (r1 == Result.Passed && r2 == Result.Passed)
                                {
                                    //第一次拍照
                                    string[] 相机3Blob = GLOBAL.cameras.GetBlobResult(
                                                   Camera.AddressOffset(
                                                    Camera.Address[3],
                                                    (int)相机3blob["起始地址"]),
                                                   (int)相机3blob["长度"]);
                                    string[] 相机4SubBlob = GLOBAL.cameras.GetSubBlobResult(
                                                   Camera.AddressOffset(
                                                    Camera.Address[4],
                                                    (int)相机4SubBlob参数["起始地址"]),
                                                   (int)相机4SubBlob参数["长度"]);
                                    //  string[] 相机3Blob = GLOBAL.cameras.GetBlobResult(Camera.Address[3], 64);
                                    //string[] 相机4边缘 = GLOBAL.cameras.GetEdgeResult(Camera.AddressOffset(Camera.Address[4], 208), 11);
                                   // string[] 相机4SubBlob = GLOBAL.cameras.GetSubBlobResult(Camera.Address[4], 64);
                                    //string[] 相机4轮廓匹配 = GLOBAL.cameras.GetContourResult(Camera.AddressOffset(Camera.Address[4], 208), 111);

                                    //sw.Start();
                                    double[] 相机3Blob1 = 相机3Blob.Select(x => Convert.ToDouble(x)).ToArray(); ;
                                    double[] 相机4SubBlob1 = { Convert.ToDouble(相机4SubBlob[0]), Convert.ToDouble(相机4SubBlob[1]) };
                                    double[] 相机4SubBlob2 = { Convert.ToDouble(相机4SubBlob[2]), Convert.ToDouble(相机4SubBlob[3]) };
                                    double radius = 0;
                                    //double[] d_相机4轮廓匹配 = 相机4轮廓匹配.Select(x => Convert.ToDouble(x)).ToArray();
                                    //double[] d_相机4Blob = 相机4SubBlob.Select(x => Convert.ToDouble(x)).ToArray();

                                    double offset_x = ((相机4SubBlob1基准点[0] - 相机4SubBlob1[0]) + (相机3Blob基准点[0] - 相机3Blob1[0])) / 2;
                                    double offset_y = ((相机4SubBlob1基准点[1] - 相机4SubBlob1[1]) + (相机3Blob基准点[1] - 相机3Blob1[1])) / 2;

                                    //将相机3点位坐标补偿至相机4坐标系
                                    相机3Blob1[0] += 相机3Blob坐标偏移[0];
                                    相机3Blob1[1] += 相机3Blob坐标偏移[1];

                                    radius = 180 * Math.Atan(
                                        (相机3Blob1[1] - 相机4SubBlob1[1])
                                        / (相机3Blob1[0] - 相机4SubBlob1[0]))
                                        / Math.PI;
                                    radius = Blob基准角度 - radius;
                                    //radius = 边缘基准角度 - Convert.ToDouble(相机4边缘[0]);
                                    //180 * ATAN((Y2- Y1) / (X2 - X1)) / PI()

                                    //double offset_x = ((SubBlob1基准点[0] - 相机4SubBlob1[0]) + (SubBlob2基准点[0] - 相机4SubBlob2[0])) / 2;
                                    //double offset_y = ((SubBlob1基准点[1] - 相机4SubBlob1[1]) + (SubBlob2基准点[1] - 相机4SubBlob2[1])) / 2;

                                    //相机4偏移[0] = center_x;
                                    //相机4偏移[1] = center_y;
                                    机器手偏移[2] = radius;

                                    string camera_data =
                                        DateTime.Now + "," + "上cg第一次相机3Blob" + "," + string.Join(",", 相机3Blob1) + "\n" +
                                        DateTime.Now + "," + "上cg第一次相机4Subblob1" + "," + string.Join(",", 相机4SubBlob1) + "\n" +
                                        //DateTime.Now + "," + "上cg第一次相机4Subblob2" + "," + string.Join(",", 相机4SubBlob2) + "\n" +
                                        DateTime.Now + "," + "上cg第一次相机4角度" + "," + 机器手偏移[2] + "\n" +
                                        DateTime.Now + "," + "上cg第一次相机4偏移" + "," + string.Join(",", offset_x, offset_y, radius);
                                    camera_log_file.WriteLine(camera_data);

                                    Log.Write("机器人第一次放料偏移:" + string.Join(",", offset_x, offset_y, radius));
                                    //sw.Stop();
                                    //Log.Write("机器人第一次放料计算时间:" + sw.Elapsed);
                                }
                                else
                                {
                                    Log.Write("上cg片相机4一次定位结果获取失败");
                                    has_wrong = true;
                                }
                                /*
                                //切换到空任务
                                GLOBAL.cameras.SelectTask(3, (int)GLOBAL.config.configs["相机参数"]["空模板"]["相机3"]);
                                //切换任务
                                GLOBAL.cameras.SelectTask(3, (int)GLOBAL.config.configs["相机参数"]["默认模板"]["相机3"]);
                                //切换到空任务
                                GLOBAL.cameras.SelectTask(4, (int)GLOBAL.config.configs["相机参数"]["空模板"]["相机4"]);
                                //切换任务
                                GLOBAL.cameras.SelectTask(4, (int)GLOBAL.config.configs["相机参数"]["默认模板"]["相机4"]);
                                */

                                //给机器人角度偏移
                                //GLOBAL.robot["机器手1"].上料机器手第一次拍照偏移(机器手偏移[0], 机器手偏移[1], 机器手偏移[2]);

                                //GLOBAL.robot["机器手1"].上料机器手第一次拍照完成();
                                //string msg = string.Join(";", 爱普生_Robot.上料机器手["机器手旋转偏移角度"], 机器手偏移[2]);//发送角度
                                //GLOBAL.robot["机器手1"].Send(msg);
                                //给机器人拍照完成信号                               
                                //GLOBAL.robot["机器手1"].Send(爱普生_Robot.上料机器手["第一次拍照完成"]);//表示第一次拍照完成

                                //Thread.Sleep(interval);

                                //等待第二次拍照信号
                                while (!GLOBAL.robot["机器手1"].上料机器手第二次拍照触发() && GLOBAL.robot["机器手1"].IsConnect && GLOBAL.cameras.IsConnect && GLOBAL.运行标志 == "1")
                                {
                                    GLOBAL.robot["机器手1"].上料机器手第一次拍照偏移(机器手偏移[0], 机器手偏移[1], 机器手偏移[2]);

                                    GLOBAL.robot["机器手1"].上料机器手第一次拍照完成();
                                    Thread.Sleep(interval);
                                }

                                r1 = Result.None;
                                r2 = Result.None;
                                /*
                                //等待第二次结果信号
                                for (int i = 0; i < max_wait; i++)
                                {
                                    Console.WriteLine("相机3" + r1.ToString());
                                    Console.WriteLine("相机4" + r2.ToString());
                                    if (r1 != Result.None && r2 != Result.None)
                                        break;
                                    r1 = GLOBAL.cameras.GetTaskStatus(3);
                                    r2 = GLOBAL.cameras.GetTaskStatus(4);
                                    Thread.Sleep(interval);
                                }
                                */

                                //Thread.Sleep(interval);
                                Thread.Sleep(debug_delay);
                                r1 = GLOBAL.cameras.GetTaskStatus(3);
                                r2 = GLOBAL.cameras.GetTaskStatus(4);
                                Log.Write("相机3:" + r1.ToString());
                                Log.Write("相机4:" + r2.ToString());
                                //第二次拍照
                                if (r1 == Result.Passed && r2 == Result.Passed)
                                {
                                    string[] 相机3Blob = GLOBAL.cameras.GetBlobResult(
                                                   Camera.AddressOffset(
                                                    Camera.Address[3],
                                                    (int)相机3blob["起始地址"]),
                                                   (int)相机3blob["长度"]);
                                    string[] 相机4SubBlob = GLOBAL.cameras.GetSubBlobResult(
                                                   Camera.AddressOffset(
                                                    Camera.Address[4],
                                                    (int)相机4SubBlob参数["起始地址"]),
                                                   (int)相机4SubBlob参数["长度"]);
                                    //string[] 相机3Blob = GLOBAL.cameras.GetBlobResult(Camera.Address[3], 64);
                                    //string[] 相机4边缘 = GLOBAL.cameras.GetEdgeResult(Camera.AddressOffset(Camera.Address[4], 208), 11);
                                    //string[] 相机4SubBlob = GLOBAL.cameras.GetSubBlobResult(Camera.Address[4], 64);
                                    //string[] 相机4轮廓匹配 = GLOBAL.cameras.GetContourResult(Camera.AddressOffset(Camera.Address[4], 208), 111);

                                    //sw.Start();
                                    double[] 相机3Blob1 = 相机3Blob.Select(x => Convert.ToDouble(x)).ToArray(); ;
                                    double[] 相机4SubBlob1 = { Convert.ToDouble(相机4SubBlob[0]), Convert.ToDouble(相机4SubBlob[1]) };
                                    double[] 相机4SubBlob2 = { Convert.ToDouble(相机4SubBlob[2]), Convert.ToDouble(相机4SubBlob[3]) };
                                    double radius = 0;
                                    //double[] d_相机4轮廓匹配 = 相机4轮廓匹配.Select(x => Convert.ToDouble(x)).ToArray();
                                    //double[] d_相机4Blob = 相机4SubBlob.Select(x => Convert.ToDouble(x)).ToArray();
                                    //将相机3点位坐标补偿至相机4坐标系

                                    double offset_x = ((相机4SubBlob1基准点[0] - 相机4SubBlob1[0]) + (相机3Blob基准点[0] - 相机3Blob1[0])) / 2;
                                    double offset_y = ((相机4SubBlob1基准点[1] - 相机4SubBlob1[1]) + (相机3Blob基准点[1] - 相机3Blob1[1])) / 2;

                                    相机3Blob1[0] += 相机3Blob坐标偏移[0];
                                    相机3Blob1[1] += 相机3Blob坐标偏移[1];

                                    radius = 180 * Math.Atan(
                                        (相机3Blob1[1] - 相机4SubBlob1[1])
                                        / (相机3Blob1[0] - 相机4SubBlob1[0]))
                                        / Math.PI;
                                    radius = Blob基准角度 - radius;
                                    //radius = 边缘基准角度 - Convert.ToDouble(相机4边缘[0]);
                                    //180 * ATAN((x2- x1) / (y2 - y1)) / PI()

                                    //double offset_x = ((SubBlob1基准点[0] - 相机4SubBlob1[0]) + (SubBlob2基准点[0] - 相机4SubBlob2[0])) / 2;
                                    //double offset_y = ((SubBlob1基准点[1] - 相机4SubBlob1[1]) + (SubBlob2基准点[1] - 相机4SubBlob2[1])) / 2;

                                    机器手偏移[0] = offset_x;
                                    机器手偏移[1] = offset_y;
                                    //相机4偏移[2] = radius;

                                    if (Math.Abs(radius) > 1)
                                    {
                                        Log.Write("cg角度矫正失败");
                                        has_wrong = true;
                                    }

                                    string camera_data =
                                        DateTime.Now + "," + "上cg第二次相机3Blob" + "," + string.Join(",", 相机3Blob1) + "\n" +
                                        DateTime.Now + "," + "上cg第二次相机4Subblob1" + "," + string.Join(",", 相机4SubBlob1) + "\n" +
                                        //DateTime.Now + "," + "上cg第二次相机4Subblob2" + "," + string.Join(",", 相机4SubBlob2) + "\n" +
                                        DateTime.Now + "," + "上cg第二次相机4角度" + "," + radius + "\n" +
                                        DateTime.Now + "," + "上cg第二次相机4偏移" + "," + string.Join(",", offset_x, offset_y, radius);
                                    camera_log_file.WriteLine(camera_data);
                                    Log.Write("机器人放料第二次偏移:" + string.Join(",", 机器手偏移[0], 机器手偏移[1], radius));
                                    //sw.Stop();
                                    //Log.Write("机器人第二次放料计算时间:" + sw.Elapsed);
                                }
                                else
                                {
                                    Log.Write("上cg片相机4二次定位结果获取失败");
                                    has_wrong = true;
                                }


                                if (has_wrong)
                                {
                                    cg_NG++;
                                    Log.Write("上cg片定位失败");
                                    GLOBAL.robot["机器手1"].拍照失败抛料();
                                }

                                if (cg_NG >= 4)
                                {
                                    GLOBAL.plc.WriteMBit(GLOBAL.config.Get("CG上料失败报警_register"), "1");
                                    cg_NG = 0;
                                }
                                
                                //切换到空任务
                                GLOBAL.cameras.SelectTask(3, (int)GLOBAL.config.configs["相机参数"]["空模板"]["相机3"]);
                                //切换任务
                                GLOBAL.cameras.SelectTask(3, (int)GLOBAL.config.configs["相机参数"]["默认模板"]["相机3"]);
                                //切换到空任务
                                GLOBAL.cameras.SelectTask(4, (int)GLOBAL.config.configs["相机参数"]["空模板"]["相机4"]);
                                //切换任务
                                GLOBAL.cameras.SelectTask(4, (int)GLOBAL.config.configs["相机参数"]["默认模板"]["相机4"]);
                                

                                //给机器人角度偏移
                                GLOBAL.robot["机器手1"].上料机器手第二次拍照偏移(机器手偏移[0], 机器手偏移[1], 机器手偏移[2]);
                                //msg = string.Join(";", 爱普生_Robot.上料机器手["机器手偏移坐标"], 机器手偏移[0], 机器手偏移[1]);//发送x,y偏移
                                //GLOBAL.robot["机器手1"].Send(msg);
                                //第二次拍照完成
                                GLOBAL.robot["机器手1"].上料机器手第二次拍照完成();
                                //GLOBAL.robot["机器手1"].Send(爱普生_Robot.上料机器手["第二次拍照完成"]);
                                //最好不要触发
                                /*
                                else if (GLOBAL.robot["机器手1"].上料机器手第二次拍照触发())
                                {
                                    Log.Write("出错上料机器手第二次拍照触发");

                                    GLOBAL.robot["机器手1"].上料机器手第二次拍照完成();
                                    //GLOBAL.robot["机器手1"].Send(爱普生_Robot.上料机器手["第二次拍照完成"]);//表示第二次拍照完成

                                }
                                */

                                error_flags["上cg错误"] = 0;
                            }


                            //Thread.Sleep(debug_delay);
                        }
                        //最好不要触发
                        else if (GLOBAL.robot["机器手1"].上料机器手第一次拍照触发())
                        {
                            Log.Write("出错上料机器手第一次拍照触发");

                            GLOBAL.robot["机器手1"].上料机器手第一次拍照完成();
                            //给机器人角度偏移
                            GLOBAL.robot["机器手1"].上料机器手第一次拍照偏移(0, 0, 0);
                            error_flags["上cg错误"] += 1;
                            //GLOBAL.robot["机器手1"].Send(爱普生_Robot.上料机器手["第二次拍照完成"]);//表示第二次拍照完成

                        }
                        //最好不要触发
                        else if (GLOBAL.robot["机器手1"].上料机器手第二次拍照触发())
                        {
                            Log.Write("出错上料机器手第二次拍照触发");

                            GLOBAL.robot["机器手1"].上料机器手第二次拍照完成();
                            GLOBAL.robot["机器手1"].上料机器手无偏移坐标();

                            error_flags["上cg错误"] += 1;

                            //切换到空任务
                            GLOBAL.cameras.SelectTask(3, (int)GLOBAL.config.configs["相机参数"]["空模板"]["相机3"]);
                            //切换任务
                            GLOBAL.cameras.SelectTask(3, (int)GLOBAL.config.configs["相机参数"]["默认模板"]["相机3"]);
                            //切换到空任务
                            GLOBAL.cameras.SelectTask(4, (int)GLOBAL.config.configs["相机参数"]["空模板"]["相机4"]);
                            //切换任务
                            GLOBAL.cameras.SelectTask(4, (int)GLOBAL.config.configs["相机参数"]["默认模板"]["相机4"]);
                            //GLOBAL.robot["机器手1"].Send(爱普生_Robot.上料机器手["第二次拍照完成"]);//表示第二次拍照完成

                        }

                        if (error_flags["上cg错误"] >= max_error)
                        {
                            GLOBAL.robot["机器手1"].DisConnect();
                            error_flags["上cg错误"] = 0;
                        }
                    }

                }
                catch (Exception e)
                {
                    Log.Write(e.ToString());
                }

                Thread.Sleep(interval);
            }
        }
        /// <summary>
        /// 扫码枪和下料机器手
        /// </summary>
        private void 下cg扫码枪触发方法()
        {
            int fail_count = 0;
            while (loop)
            {
                try
                {
                    if (GLOBAL.robot["机器手2"].IsConnect && GLOBAL.扫码枪["扫码枪2"].IsConnect&&GLOBAL.运行标志=="1")
                    {
                        if (GLOBAL.robot["机器手2"].下料机器手第一次扫码触发())
                        {

                            //给机器人扫码完成信号
                            /*
                            //未取到结果时循环重试
                            if (取扫码枪结果失败)
                            GLOBAL.robot["机器手2"].Send(Robot.下料机器手["扫码枪取结果失败标志1"]);//表示第一次扫码未完成
                            //等待再次拍照信号
                            while (!GLOBAL.robot["机器手2"].下料机器手第一次扫码触发())
                            {
                                if (!GLOBAL.robot["机器手2"].IsConnect)
                                    break;
                                Thread.Sleep(interval);
                            }
                            */
                            Thread.Sleep(interval);//等待回环线动作

                            string[] result = new string[] { };

                            bool 扫码结果 = false;
                            for(int i = 0;i < max_fail;i++)
                            {
                                if(!扫码结果&& GLOBAL.扫码枪["扫码枪2"].IsConnect)
                                    扫码结果 = GLOBAL.扫码枪["扫码枪2"].GetBarCode(ref result);//扫码结果标志,均失败则ng
                                else
                                    i = max_fail;
                                Thread.Sleep(interval);
                            }

                            if (GLOBAL.config.Get("扫码_enable") == "否")
                            {
                                Log.Write("扫码未启用");
                                扫码结果 = true;
                            }

                            //string[] codeArray = result.Split(';');

                            if (扫码结果)
                            {
                                var 参数上传json = GLOBAL.station[1].Tray.Product.Report;
                                var 绑码json = 初始化过站绑码();
                                var prod_data = new JArray();
                                //当回环线没跟上时取前一个载具
                                if (参数上传json == null)
                                {
                                    //没数据再取一下焊接数据
                                    参数上传json = GLOBAL.station[0].Tray.Product.Report;
                                    if (参数上传json == null)
                                        参数上传json = 初始化焊接参数();

                                    prod_data = (JArray)参数上传json["prod_data"];
                                }
                                else
                                    prod_data = (JArray)参数上传json["prod_data"];


                                if (prod_data.Count == 0)
                                {
                                    List<JObject> r1;
                                    if (GLOBAL.laser["激光机台1"].获取屏蔽片焊接数据(out r1))
                                    {
                                        //var jarr = new JArray();

                                        r1.ForEach(j => prod_data.Add(j));

                                    }
                                    else
                                        Log.Write("激光机台1获取焊接参数失败");


                                    List<JObject> r2;
                                    if (GLOBAL.laser["激光机台2"].获取螺母焊接数据(out r2))
                                    {
                                        //var jarr = GLOBAL.station[7].Tray.Product.Report["prod_data"] as JArray;

                                        r2.ForEach(j => prod_data.Add(j));

                                    }
                                    else
                                        Log.Write("激光机台2获取焊接参数失败");

                                    参数上传json["prod_data"] = prod_data;
                                }

                                foreach (var b in result)
                                {
                                    var barcodes = b.Split(';');
                                    if(barcodes.Length == 2)
                                    {
                                        GLOBAL.统计数据.下CG_Count_OK++;

                                        Log.Write(GLOBAL.station[1].Tray.ID + "载具条码:" + barcodes[0]);
                                        Log.Write(GLOBAL.station[1].Tray.ID + "CG条码:" + barcodes[1]);
                                        GLOBAL.station[1].Tray.Barcode = barcodes[0];
                                        GLOBAL.station[1].Tray.Product.Barcode = barcodes[1];
                                        GLOBAL.下料位状态.Barcode = barcodes[0];
                                        GLOBAL.下料位状态.Product.Barcode = barcodes[1];

                                        var jarr = 绑码json["bind_code"] as JArray;
                                        jarr[0]["code_sn"] = barcodes[0];
                                        绑码json["bind_code"] = jarr;
                                        绑码json["prod_barcode"] = barcodes[1];

                                        参数上传json["fixture"] = barcodes[0];
                                        参数上传json["frame_barcode"] = barcodes[1];
                                        //参数上传json["end_time"] = DateTime.Now.ToString("yyyyMMddHHmmss");

                                        bool 绑码结果 = false;

                                        if (GLOBAL.config.Get("SFC_enable") == "是")
                                        {
                                            var t1 = GLOBAL.sfc.过站绑码(绑码json);
                                            t1.Wait();
                                            绑码结果 = t1.Result;

                                            if (绑码结果)
                                            {
                                                Log.Write(barcodes[1] + "过站绑码成功");
                                                Console.WriteLine(barcodes[1] + "过站绑码成功");

                                                var t2 = GLOBAL.sfc.参数上传(参数上传json);
                                                t2.Wait();
                                                var 参数上传结果 = t2.Result;

                                                if (参数上传结果)
                                                {
                                                    Log.Write(barcodes[1] + "参数上传成功");
                                                    Console.WriteLine(barcodes[1] + "参数上传成功");

                                                }
                                                else
                                                {

                                                    Log.Write(barcodes[1] + "参数上传失败");
                                                    Console.WriteLine(barcodes[1] + "参数上传失败");
                                                }
                                            }
                                            else
                                            {

                                                Log.Write(barcodes[1] + "过站绑码失败");
                                                Console.WriteLine(barcodes[1] + "过站绑码失败");
                                            }
                                        }
                                        else
                                            Log.Write("SFC未启用");
                                    }
                                    break;
                                }
                                GLOBAL.robot["机器手2"].下料扫码成功();
                                //GLOBAL.robot["机器手2"].Send(爱普生_Robot.下料机器手["下料扫码成功"]);
                                //Console.WriteLine("SFC过站报告:" + json.ToString());
                                

                            }
                            else
                            {
                                GLOBAL.统计数据.下CG_Count_NG++;
                                Log.Write("下料扫码失败"+ string.Join("", result));
                                GLOBAL.robot["机器手2"].下料扫码失败();
                                //GLOBAL.robot["机器手2"].Send(爱普生_Robot.下料机器手["下料扫码失败"]);
                            }
                            GLOBAL.robot["机器手2"].下料机器手扫码完成();
                            //GLOBAL.robot["机器手2"].Send(爱普生_Robot.下料机器手["扫码枪取结果完成标志1"]);//表示第一次扫码完成

                            //回环线debug信息();
                            GLOBAL.station[1].Tray.Barcode = "";
                            GLOBAL.station[1].Tray.Product = new Product();
                            GLOBAL.station[1].Tray.有CG片 = false;
                            GLOBAL.station[1].Tray.有大螺母 = false;
                            GLOBAL.station[1].Tray.有小螺母 = false;
                            GLOBAL.station[1].Tray.有屏蔽片 = false;

                        }
                        //等待第二次拍照信号
                        else if (GLOBAL.robot["机器手2"].下料机器手第二次扫码触发())
                        {

                            Thread.Sleep(interval);//等待回环线动作
                            /*
                            string result = "";
                            GLOBAL.扫码枪["扫码枪2"].GetBarCode(ref result);
                            Log.Write(GLOBAL.station[1].Tray.ID + "载具条码:" + result);

                            //暂时只变更这些状态
                            GLOBAL.station[1].Tray.Barcode = result;
                            GLOBAL.下料位状态.ID = GLOBAL.station[1].Tray.ID;
                            GLOBAL.下料位状态.Barcode = GLOBAL.station[1].Tray.Barcode;
                            GLOBAL.下料位状态.Product.Barcode = GLOBAL.station[1].Tray.Product.Barcode;
                            */
                            GLOBAL.robot["机器手2"].下料机器手第二次扫码完成();
                            //GLOBAL.robot["机器手2"].Send(爱普生_Robot.下料机器手["扫码枪取结果完成标志2"]);//表示第二次扫码完成
                            //回环线debug信息();
                            /*
                            GLOBAL.station[1].Tray.Barcode = "";
                            GLOBAL.station[1].Tray.Product = new Product();
                            GLOBAL.station[1].Tray.有CG片 = false;
                            GLOBAL.station[1].Tray.有大螺母 = false;
                            GLOBAL.station[1].Tray.有小螺母 = false;
                            GLOBAL.station[1].Tray.有屏蔽片 = false;
                            */
                        }
                        else if (GLOBAL.robot["机器手2"].下料完成())
                        {
                            Log.Write("下料机器手放料完成");
                            GLOBAL.plc.WriteMBit(GLOBAL.config.Get("下料计数_register"), "1");
                            Thread.Sleep(interval);
                            GLOBAL.plc.WriteMBit(GLOBAL.config.Get("下料计数_register"), "0");
                            // GLOBAL.robot["机器手2"].下料完成标志复位();
                        }
                        //取料失败
                        //if (GLOBAL.robot["机器手2"].下料机器手取料失败())
                        //{

                        //    Log.Write("下料机器手取料失败");
                        //    GLOBAL.robot["机器手2"].Send(爱普生_Robot.下料机器手["下料机器手取料失败标志复位"]);
                        //    Thread.Sleep(interval);
                        //   // GLOBAL.plc.WriteMBit(GLOBAL.config.Get("下料ROBOT取料失败_register"), "1");
                            
                        //}
                    }

                }
                catch (Exception e)
                {
                    Log.Write(e.ToString());
                }
                Thread.Sleep(interval);
            }
        }

        /// <summary>
        /// 刷新plc数据
        /// </summary>
        private void 刷新PLC方法()
        {
            while (loop)
            {
                try
                {
                    if (GLOBAL.plc.IsConnect)
                    {
                        GLOBAL.plc.RefreshMBit();
                        GLOBAL.plc.ReadMBit(GLOBAL.config.Get("运行标志_register"), ref GLOBAL.运行标志);
                    }
                }
                catch (Exception e)
                {
                    Log.Write(e.ToString());
                }
                System.Threading.Thread.Sleep(10);
            }
        }

        /// <summary>
        /// 模拟回环线
        /// </summary>
        private void 模拟回环线方法()
        {
            DateTime 上次动作时间 = DateTime.Now;
            while (loop)
            {
                try
                {
                    if (GLOBAL.plc.IsConnect && GLOBAL.运行标志 == "1")
                    {
                        string 回环线1BUSY = "0";
                        //string 回环线2BUSY = "0";
                        string 回环线3BUSY = "0";
                        //string 回环线4BUSY = "0";
                        GLOBAL.plc.ReadMBit(GLOBAL.config.Get("回环线1BUSY_register"), ref 回环线1BUSY);
                        //GLOBAL.plc.ReadMBit(GLOBAL.config.Get("回环线2BUSY_register"), ref 回环线2BUSY);
                        GLOBAL.plc.ReadMBit(GLOBAL.config.Get("回环线3BUSY_register"), ref 回环线3BUSY);
                        //GLOBAL.plc.ReadMBit(GLOBAL.config.Get("回环线4BUSY_register"), ref 回环线4BUSY);
                        //回环线1动作触发
                        if (回环线1BUSY == "1")
                        {
                            GLOBAL.统计数据.回环线动作数++;
                            DateTime 当前时间 = DateTime.Now;
                            TimeSpan 回环线动作间隔 = 当前时间 - 上次动作时间;
                            if (回环线动作间隔.TotalSeconds > 60)
                            {
                                上次动作时间 = 当前时间;
                            }
                            else
                            {
                                上次动作时间 = 当前时间;
                                GLOBAL.统计数据.Time_per_round.Add(回环线动作间隔);
                                //System.Console.WriteLine(回环线动作间隔);
                                var total_time = new TimeSpan(0);
                                GLOBAL.统计数据.Time_per_round.ForEach(f => total_time += f);
                                //System.Console.WriteLine(total_time);

                                GLOBAL.统计数据.回环线动作平均时间 = TimeSpan.FromSeconds(total_time.TotalSeconds / GLOBAL.统计数据.Time_per_round.Count);
                                //System.Console.WriteLine(GLOBAL.统计数据.回环线动作平均时间);
                            }

                            //触发后
                            var json = 初始化焊接参数();
                            //json["start_time"] = DateTime.Now.ToString("yyyyMMddHHmmss");
                            GLOBAL.station[4].Tray.Product.Report = json;

                            //将要转移到中转工位的载具
                            Tray temp = GLOBAL.station[4].Tray;
                            //4->3->2->1->0依次后移
                            for (int i = 4; i > 0; i--)
                            {
                                GLOBAL.station[i].Tray = GLOBAL.station[i - 1].Tray;
                            }

                            if (GLOBAL.station[1].Tray.Product.屏蔽片焊接失败 == 1)
                            {
                                Log.Write("屏蔽片焊接失败抛料");
                                GLOBAL.robot["机器手2"].下料扫码失败();
                                //GLOBAL.robot["机器手2"].Send(爱普生_Robot.下料机器手["下料扫码失败"]);
                                GLOBAL.station[1].Tray.Product.屏蔽片焊接失败 = 0;
                            }
                            //将temp转移到中转工位
                            GLOBAL.station[0].Tray = temp;
                            //状态变更测试
                            GLOBAL.station[4].Tray.有CG片 = true;

                            //回环线debug信息();

                            //等待动作完成退出
                            while (回环线1BUSY == "1" && GLOBAL.运行标志 == "1" && GLOBAL.plc.IsConnect)
                            {
                                GLOBAL.plc.ReadMBit(GLOBAL.config.Get("回环线1BUSY_register"), ref 回环线1BUSY);
                                Thread.Sleep(interval);
                            }
                        }
                        //回环线3动作触发
                        if (回环线3BUSY == "1")
                        {
                            //触发后
                            //将要转移到中转工位的载具
                            Tray temp = GLOBAL.station[8].Tray;
                            //8->7->6->5->0依次后移
                            for (int i = 8; i > 4; i--)
                            {
                                GLOBAL.station[i].Tray = GLOBAL.station[i - 1].Tray;
                            }
                            GLOBAL.station[5].Tray = GLOBAL.station[0].Tray;
                            //将temp转移到中转工位
                            GLOBAL.station[0].Tray = temp;

                            //回环线debug信息();

                            //等待动作完成退出
                            while (回环线3BUSY == "1" && GLOBAL.运行标志 == "1" && GLOBAL.plc.IsConnect)
                            {
                                GLOBAL.plc.ReadMBit(GLOBAL.config.Get("回环线3BUSY_register"), ref 回环线3BUSY);
                                Thread.Sleep(interval);
                            }


                            //触发后
                            if(GLOBAL.station[6].Tray.Product.Report == null)
                            {
                                var json = 初始化焊接参数();
                                //json["start_time"] = DateTime.Now.ToString("yyyyMMddHHmmss");
                                GLOBAL.station[6].Tray.Product.Report = json;
                            }

                            if (GLOBAL.station[7].Tray.Product.Report == null)
                            {
                                var json = 初始化焊接参数();
                                //json["start_time"] = DateTime.Now.ToString("yyyyMMddHHmmss");
                                GLOBAL.station[7].Tray.Product.Report = json;
                            }

                            //if (GLOBAL.station[6].Tray.有屏蔽片)
                            {
                                List<JObject> result;
                                if(GLOBAL.laser["激光机台1"].获取屏蔽片焊接数据(out result))
                                {
                                    var jarr = new JArray();
                                    
                                    result.ForEach(j => jarr.Add(j));
                                    GLOBAL.station[6].Tray.Product.Report["prod_data"] = jarr;

                                }
                                else
                                    Log.Write("激光机台1获取焊接参数失败");
                                    //Console.WriteLine("激光机台1获取焊接参数失败");
                            }
                            //if (GLOBAL.station[7].Tray.有屏蔽片)
                            {

                                List<JObject> result;
                                if (GLOBAL.laser["激光机台2"].获取螺母焊接数据(out result))
                                {
                                    var jarr = GLOBAL.station[7].Tray.Product.Report["prod_data"] as JArray;

                                    result.ForEach(j => jarr.Add(j));
                                    GLOBAL.station[7].Tray.Product.Report["prod_data"] = jarr;

                                }
                                else
                                    Log.Write("激光机台2获取焊接参数失败");
                                    //Console.WriteLine("激光机台2获取焊接参数失败");
                            }
                        }

                        //回环线动作数据限制在600条
                        if (GLOBAL.统计数据.Time_per_round.Count > 600)
                            GLOBAL.统计数据.Time_per_round.RemoveAt(0);
                    }
                }
                catch (Exception e)
                {
                    Log.Write(e.ToString());
                }
                System.Threading.Thread.Sleep(interval);
            }
        }

        private void 回环线debug信息()
        {
            //调试信息
            Console.WriteLine("中转工位:\n" +
                        GLOBAL.station[0].Tray.ID + " : " +
                        "条码:" + GLOBAL.station[0].Tray.Barcode + "," +
                        "有CG片:" + GLOBAL.station[0].Tray.有CG片 + "," +
                        "CG片条码:" + GLOBAL.station[0].Tray.Product.Barcode + "," +
                        "有大螺母:" + GLOBAL.station[0].Tray.有大螺母 + "," +
                        "有小螺母:" + GLOBAL.station[0].Tray.有小螺母 + "," +
                        "有屏蔽片:" + GLOBAL.station[0].Tray.有屏蔽片);
            Console.WriteLine("回环线1: ");
            for (int i = 1; i < 9; i++)
            {
                if (i == 5)
                    Console.WriteLine("回环线3: ");

                Console.WriteLine(
                            GLOBAL.station[i].Tray.ID + " : " +
                            "条码:" + GLOBAL.station[i].Tray.Barcode + "," +
                            "有CG片:" + GLOBAL.station[i].Tray.有CG片 + "," +
                            "CG片条码:" + GLOBAL.station[i].Tray.Product.Barcode + "," +
                            "有大螺母:" + GLOBAL.station[i].Tray.有大螺母 + "," +
                            "有小螺母:" + GLOBAL.station[i].Tray.有小螺母 + "," +
                            "有屏蔽片:" + GLOBAL.station[i].Tray.有屏蔽片);

            }

        }
        private void 保存打印警告信息()
        {
            //warning, start time 
            Dictionary<string, DateTime> warnings = new Dictionary<string, DateTime>();
            string[] last_warning = new string[] { };
            //string result = "";
            while (loop)
            {
                try
                {
                    if (GLOBAL.plc.IsConnect)
                    {
                        string warning_result = "";
                        List<string> warning_info_list = new List<string>();
                        string[] warning_msg = GLOBAL.plc.ReadMWarning();
                        //string[] intersection =warning_register.Intersect(temp).ToArray();
                        string[] exception = warning_msg.Except(last_warning).ToArray();

                        if (warning_msg.Contains("总警告"))
                            GLOBAL.总警告 = "1";
                        else
                            GLOBAL.总警告 = "0";

                        if (exception.Length > 0)
                        {

                            //warning_result += DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + "," + string.Join(",", warning_msg);
                            foreach(var s in exception)
                            {
                                if (!warnings.ContainsKey(s))
                                {
                                    warnings[s] = DateTime.Now;
                                }
                                else
                                {
                                    warning_result += s + "," + warnings[s].ToString("yyyy-MM-dd HH:mm:ss") + "," + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + "\r\n";
                                    warnings.Remove(s);
                                }
                            }

                            GLOBAL.统计数据.Warning_stack = string.Join("\r\n", warning_msg);
                            
                            //warning_file.WriteLine(warning_result);
                            warning_file.Write(warning_result);
                            Log.Write(string.Join(",", warning_msg));
                        }

                        last_warning = warning_msg;

                        string 屏蔽片焊接失败 = "";
                        GLOBAL.plc.ReadMBit(GLOBAL.config.Get("屏蔽片焊接失败_register"), ref 屏蔽片焊接失败);
                        if (屏蔽片焊接失败 == "1")
                        {
                            Log.Write("屏蔽片焊接失败");
                            GLOBAL.station[6].Tray.Product.屏蔽片焊接失败 = 1;
                            GLOBAL.plc.WriteMBit(GLOBAL.config.Get("屏蔽片焊接失败_register"), "0");
                        }
                        //保持在线信号
                        //GLOBAL.plc.WriteMBit(GLOBAL.config.Get("上位机软件在线信号_register"), "1");
                    }


                    GLOBAL.统计数据.运行时间 = DateTime.Now - GLOBAL.统计数据.启动时间;
                }
                catch (Exception e)
                {
                    Console.WriteLine(e.ToString());
                }
                Thread.Sleep(500);
            }
        }

        private int 角度转换上螺母脉冲(double radius)
        {
            return (int)(radius * 角度转换上螺母脉冲系数);
        }
        private int 角度转换上屏蔽片脉冲(double radius)
        {
            return (int)(radius * 角度转换上屏蔽片脉冲系数);
        }
        private int OffsetToPulse(double offset)
        {
            return (int)(offset * OffsetToPulse系数);
        }

        private JObject 获取上料确认数据()
        {
            var json = GLOBAL.config.configs["SFC_上料确认demo"].DeepClone() as JObject;
            return json;
        }
        private JObject 初始化过站签收()
        {
            var json = GLOBAL.config.configs["SFC_过站demo"].DeepClone() as JObject;
            return json;
        }
        private JObject 初始化过站绑码()
        {
            var json = GLOBAL.config.configs["SFC_绑码demo"].DeepClone() as JObject;
            return json;
        }
        private JObject 初始化焊接参数()
        {
            var json = GLOBAL.config.configs["SFC_参数上传demo"].DeepClone() as JObject;
            return json;
        }
    }
}